From c038489151eb2590b06e12e4cae48aa18e29bf79 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Mon, 7 Aug 2023 21:51:49 +0300 Subject: [PATCH 01/31] wip --- wondrous-bot-admin/index.html | 3 ++ wondrous-bot-admin/src/App.tsx | 5 ++ wondrous-bot-admin/src/main.tsx | 2 +- .../src/pages/telegram/index.tsx | 47 +++++++++++++++++++ wondrous-bot-admin/src/utils/constants.tsx | 2 + 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 wondrous-bot-admin/src/pages/telegram/index.tsx diff --git a/wondrous-bot-admin/index.html b/wondrous-bot-admin/index.html index 035d060ceb..b9dcf6bc86 100644 --- a/wondrous-bot-admin/index.html +++ b/wondrous-bot-admin/index.html @@ -5,6 +5,7 @@ +
+ + diff --git a/wondrous-bot-admin/src/App.tsx b/wondrous-bot-admin/src/App.tsx index d5a429563f..97039d0268 100644 --- a/wondrous-bot-admin/src/App.tsx +++ b/wondrous-bot-admin/src/App.tsx @@ -44,6 +44,7 @@ import VerifyLinkPage from "pages/verify-link"; import AnalyticsPage from "pages/analytics"; import PremiumFeatureDialog from "components/PremiumFeatureDialog"; import PaywallContext from "utils/context/PaywallContext"; +import TelegramPage from "pages/telegram"; const router = createBrowserRouter([ { @@ -160,6 +161,10 @@ const router = createBrowserRouter([ { path: '/analytics', element: + }, + { + path: '/telegram', + element: } ], }, diff --git a/wondrous-bot-admin/src/main.tsx b/wondrous-bot-admin/src/main.tsx index ba8922c13a..1c3d805501 100644 --- a/wondrous-bot-admin/src/main.tsx +++ b/wondrous-bot-admin/src/main.tsx @@ -7,7 +7,7 @@ declare global { if (typeof window !== "undefined") { window.global = window; - window.Buffer = Buffer; + // window.Buffer = Buffer; } import React from "react"; import ReactDOM from "react-dom/client"; diff --git a/wondrous-bot-admin/src/pages/telegram/index.tsx b/wondrous-bot-admin/src/pages/telegram/index.tsx new file mode 100644 index 0000000000..b4ea9982eb --- /dev/null +++ b/wondrous-bot-admin/src/pages/telegram/index.tsx @@ -0,0 +1,47 @@ +import React, { useEffect } from "react"; + +const TelegramPage = () => { + let tg = (window as any).Telegram.WebApp; + + useEffect(() => { + // Define the onTelegramAuth function on the global scope + (window as any).onTelegramAuth = (user) => { + console.log(user, 'UUUUSER') + alert( + "Logged in as " + + user.first_name + + " " + + user.last_name + + " (" + + user.id + + (user.username ? ", @" + user.username : "") + + ")" + ); + }; + + // Create and append the script tag + const script = document.createElement("script"); + script.async = true; + script.src = "https://telegram.org/js/telegram-widget.js?22"; + script.setAttribute("data-telegram-login", "communities_test_bot"); + script.setAttribute("data-size", "large"); + script.setAttribute("data-onauth", "onTelegramAuth(user)"); + script.setAttribute("data-request-access", "write"); + document.body.appendChild(script); + + // Cleanup: remove script when component unmounts + return () => { + document.body.removeChild(script); + }; + }, []); + + tg.expand(); + + return ( +
+

{JSON.stringify(tg)}

+
+ ); +}; + +export default TelegramPage; diff --git a/wondrous-bot-admin/src/utils/constants.tsx b/wondrous-bot-admin/src/utils/constants.tsx index 62f70708e0..6b232d0e22 100644 --- a/wondrous-bot-admin/src/utils/constants.tsx +++ b/wondrous-bot-admin/src/utils/constants.tsx @@ -99,6 +99,7 @@ export const PAGES_WITHOUT_HEADER = [ "/discord/callback/cmty-user-connect", "/invite/:token", "/verify-link", + '/telegram' ]; export const BG_TYPES = { @@ -306,6 +307,7 @@ export const EXCLUDED_PATHS = [ "/invite/:token", "/verify-link", "/wallet/connect", + "/telegram" ]; export const TUTORIALS = { From 41886a3bda05fa13a7e95daab95d761a6a5917df Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Tue, 8 Aug 2023 20:19:51 +0300 Subject: [PATCH 02/31] settings page --- wondrous-bot-admin/src/App.tsx | 5 + .../components/ConnectBotComponent/index.tsx | 155 ++++++++++++++++++ .../components/ConnectBotComponent/styles.tsx | 53 ++++++ .../src/components/Icons/Discord.tsx | 36 ++-- .../src/components/Icons/ExternalLink.tsx | 12 ++ .../src/components/Icons/Telegram.tsx | 17 ++ .../src/components/Settings/MenuSwitcher.tsx | 4 + .../src/pages/settings/connect.tsx | 37 +++++ 8 files changed, 301 insertions(+), 18 deletions(-) create mode 100644 wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx create mode 100644 wondrous-bot-admin/src/components/ConnectBotComponent/styles.tsx create mode 100644 wondrous-bot-admin/src/components/Icons/ExternalLink.tsx create mode 100644 wondrous-bot-admin/src/components/Icons/Telegram.tsx create mode 100644 wondrous-bot-admin/src/pages/settings/connect.tsx diff --git a/wondrous-bot-admin/src/App.tsx b/wondrous-bot-admin/src/App.tsx index 97039d0268..92e2bc5898 100644 --- a/wondrous-bot-admin/src/App.tsx +++ b/wondrous-bot-admin/src/App.tsx @@ -45,6 +45,7 @@ import AnalyticsPage from "pages/analytics"; import PremiumFeatureDialog from "components/PremiumFeatureDialog"; import PaywallContext from "utils/context/PaywallContext"; import TelegramPage from "pages/telegram"; +import ConnectPage from "pages/settings/connect"; const router = createBrowserRouter([ { @@ -74,6 +75,10 @@ const router = createBrowserRouter([ path: "/settings/billing", element: , }, + { + path: '/settings/connect', + element: + }, { path: "/", element: , diff --git a/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx b/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx new file mode 100644 index 0000000000..9ac18407ad --- /dev/null +++ b/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx @@ -0,0 +1,155 @@ +import { Box, ButtonBase, Grid, Typography } from "@mui/material"; +import { getDiscordBotOauthURL } from "components/ConnectDiscord/ConnectDiscordButton"; +import { GreenBgDiscord } from "components/Icons/Discord"; +import { TelegramGreenBg } from "components/Icons/Telegram"; +import { NotificationWrapper } from "components/Settings/NotificationSettings/styles"; +import { SharedSecondaryButton } from "components/Shared/styles"; +import { useContext, useState } from "react"; +import GlobalContext from "utils/context/GlobalContext"; +import { AddBotLink, SharedLabel, StatusPill } from "./styles"; +import OpenInNewIcon from "@mui/icons-material/OpenInNew"; +import { ExternalLinkIcon } from "components/Icons/ExternalLink"; +import { CustomTextField } from "components/AddFormEntity/components/styles"; + +const useTelegramModal = () => { + const [isTelegramModalOpen, setIsTelegramModalOpen] = useState(false); + const toggleTelegramModal = () => setIsTelegramModalOpen((prev) => !prev); + const [groupId, setGroupId] = useState(""); + const [error, setError] = useState(''); + + const handleSubmit = () => { + console.log('SUBMIT') + }; + + const TgComponent = () => { + const handleChange = (e) => setGroupId(e.target.value); + + const config = [ + { + label: "Link WonderBot", + component: () => ( + + Add Bot + + + ), + }, + { + label: "Group ID", + component: () => , + }, + ]; + if (!isTelegramModalOpen) return null; + return ( + + + {config.map((item, idx) => { + return ( + + + {`${idx + 1}. ${item.label}`} + + {item.component()} + + ); + })} + + + Connect + + + ); + }; + + const ConnectButton = () => { + if (isTelegramModalOpen) { + return ( + + + Cancel + + + ); + } + return Connect; + }; + return { + TgComponent, + ConnectButton, + }; +}; + +const ConnectBotComponent = () => { + const { activeOrg } = useContext(GlobalContext); + const oauthUrl = getDiscordBotOauthURL({ orgId: activeOrg?.id }); + const { TgComponent, ConnectButton } = useTelegramModal(); + const handleDiscordClick = async () => { + window.location.href = oauthUrl; + }; + + const CARDS_CONFIG = [ + { + title: "Discord", + icon: GreenBgDiscord, + onClick: handleDiscordClick, + isConnected: !!activeOrg?.cmtyDiscordConfig, + }, + { + title: "Telegram", + icon: TelegramGreenBg, + component: TgComponent, + customButton: ConnectButton, + }, + ]; + + return ( + + You can connect your bot to either or both platforms below. + + {CARDS_CONFIG.map((card) => ( + + + + {card.title} + + {card.customButton ? ( + card.customButton() + ) : ( + <> + {card.isConnected ? ( + Connected + ) : ( + Connect + )} + + )} + + + {card.component && <>{card.component()}} + + ))} + + + ); +}; + +export default ConnectBotComponent; diff --git a/wondrous-bot-admin/src/components/ConnectBotComponent/styles.tsx b/wondrous-bot-admin/src/components/ConnectBotComponent/styles.tsx new file mode 100644 index 0000000000..0aec9ad9b6 --- /dev/null +++ b/wondrous-bot-admin/src/components/ConnectBotComponent/styles.tsx @@ -0,0 +1,53 @@ +import { Button, ButtonBase, Typography } from "@mui/material"; +import styled from "styled-components"; + +export const SharedLabel = styled(Typography)` + && { + font-family: Poppins; + font-style: normal; + font-weight: 500; + font-size: 15px; + line-height: 24px; + color: black; + } +`; + +export const StatusPill = styled(ButtonBase)` + && { + padding: 8px 24px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 35px; + height: 40px; + min-width: 40px; + width: auto; + color: #2a8d5c; + font-family: "Poppins"; + font-style: normal; + font-weight: 600; + font-size: 15px; + border: 1px solid #2a8d5c; + } +`; + +export const AddBotLink = styled(ButtonBase)` + && { + display: flex; + height: 40px; + width: 100%; + padding: 6px 10px; + justify-content: space-between; + color: #000; + font-family: Poppins; + font-size: 15px; + font-style: normal; + font-weight: 500; + line-height: 15px; /* 100% */ + align-items: center; + gap: 14px; + align-self: stretch; + border-radius: 6px; + background: #c1b6f6; + } +`; diff --git a/wondrous-bot-admin/src/components/Icons/Discord.tsx b/wondrous-bot-admin/src/components/Icons/Discord.tsx index 0003b18b46..ab8abdfaba 100644 --- a/wondrous-bot-admin/src/components/Icons/Discord.tsx +++ b/wondrous-bot-admin/src/components/Icons/Discord.tsx @@ -1,32 +1,32 @@ export const WhiteBgDiscord = () => ( - + ); export const ShapedHexagonWrapper = () => ( - + {/* 1 */} ); + +export const GreenBgDiscord = () => ( + + + + +); diff --git a/wondrous-bot-admin/src/components/Icons/ExternalLink.tsx b/wondrous-bot-admin/src/components/Icons/ExternalLink.tsx new file mode 100644 index 0000000000..a18c4a970a --- /dev/null +++ b/wondrous-bot-admin/src/components/Icons/ExternalLink.tsx @@ -0,0 +1,12 @@ +export const ExternalLinkIcon = () => ( + + + + + +); diff --git a/wondrous-bot-admin/src/components/Icons/Telegram.tsx b/wondrous-bot-admin/src/components/Icons/Telegram.tsx new file mode 100644 index 0000000000..22c9db34d2 --- /dev/null +++ b/wondrous-bot-admin/src/components/Icons/Telegram.tsx @@ -0,0 +1,17 @@ +export const TelegramGreenBg = () => ( + + + + + + +); diff --git a/wondrous-bot-admin/src/components/Settings/MenuSwitcher.tsx b/wondrous-bot-admin/src/components/Settings/MenuSwitcher.tsx index fda78c10e3..bd0491fcd1 100644 --- a/wondrous-bot-admin/src/components/Settings/MenuSwitcher.tsx +++ b/wondrous-bot-admin/src/components/Settings/MenuSwitcher.tsx @@ -12,6 +12,10 @@ const MENU_ITEMS = [ title: "Notifications", path: "/settings/notifications", }, + { + title: 'Connect Bot', + path: '/settings/connect' + }, { title: "Payments", path: "/settings/payments", diff --git a/wondrous-bot-admin/src/pages/settings/connect.tsx b/wondrous-bot-admin/src/pages/settings/connect.tsx new file mode 100644 index 0000000000..aed00ecd25 --- /dev/null +++ b/wondrous-bot-admin/src/pages/settings/connect.tsx @@ -0,0 +1,37 @@ +import ConnectBotComponent from "components/ConnectBotComponent"; +import PageHeader from "components/PageHeader"; +import { MenuSwitcher } from "components/Settings"; +import PageWrapper from "components/Shared/PageWrapper"; +import { BG_TYPES } from "utils/constants"; + +//TODO - add shared component +const ConnectPage = () => { + return ( + <> + + + + + + + ); +}; + +export default ConnectPage; From e23462ea9543e324f9b7544ff772dcc8ddf5a8a5 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Wed, 9 Aug 2023 15:01:40 +0300 Subject: [PATCH 03/31] tg page --- .../components/ConnectBotComponent/index.tsx | 91 ++++++++++++++++--- .../src/graphql/mutations/index.ts | 3 +- .../src/graphql/mutations/telegram.ts | 10 ++ .../src/graphql/queries/telegram.ts | 10 ++ .../src/utils/discord/index.tsx | 6 +- 5 files changed, 106 insertions(+), 14 deletions(-) create mode 100644 wondrous-bot-admin/src/graphql/mutations/telegram.ts create mode 100644 wondrous-bot-admin/src/graphql/queries/telegram.ts diff --git a/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx b/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx index 9ac18407ad..87604fe53e 100644 --- a/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx +++ b/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx @@ -3,43 +3,106 @@ import { getDiscordBotOauthURL } from "components/ConnectDiscord/ConnectDiscordB import { GreenBgDiscord } from "components/Icons/Discord"; import { TelegramGreenBg } from "components/Icons/Telegram"; import { NotificationWrapper } from "components/Settings/NotificationSettings/styles"; -import { SharedSecondaryButton } from "components/Shared/styles"; -import { useContext, useState } from "react"; +import { ErrorText, SharedSecondaryButton } from "components/Shared/styles"; +import { useContext, useEffect, useState } from "react"; import GlobalContext from "utils/context/GlobalContext"; import { AddBotLink, SharedLabel, StatusPill } from "./styles"; import OpenInNewIcon from "@mui/icons-material/OpenInNew"; import { ExternalLinkIcon } from "components/Icons/ExternalLink"; import { CustomTextField } from "components/AddFormEntity/components/styles"; +import { getTelegramBotLink } from "utils/discord"; +import { useLazyQuery, useMutation } from "@apollo/client"; +import * as yup from "yup"; +import { CONNECT_TELEGRAM_BOT } from "graphql/mutations"; +import { GET_TELEGRAM_CONFIG_FOR_ORG } from "graphql/queries/telegram"; + +const telegramGroupIdSchema = yup + .number() + .integer("ID must be an integer.") + .negative("ID must be negative.") + .required("ID is required."); + +const validateTelegramGroupId = async (groupId) => { + try { + await telegramGroupIdSchema.validate(groupId); + return true; + } catch (error) { + console.error(error.message); + return false; + } +}; const useTelegramModal = () => { + const { activeOrg } = useContext(GlobalContext); + const [isTelegramModalOpen, setIsTelegramModalOpen] = useState(false); const toggleTelegramModal = () => setIsTelegramModalOpen((prev) => !prev); const [groupId, setGroupId] = useState(""); - const [error, setError] = useState(''); + const [error, setError] = useState(""); + + const [getTelegramConfigForOrg, { data }] = useLazyQuery(GET_TELEGRAM_CONFIG_FOR_ORG, { + onCompleted: (data) => { + if (data?.getTelegramConfigForOrg?.chatId) { + setGroupId(data?.getTelegramConfigForOrg?.chatId); + } + }, + }); + + const [connectTelegram] = useMutation(CONNECT_TELEGRAM_BOT, { + refetchQueries: ["getTelegramConfigForOrg"], + onCompleted: () => { + toggleTelegramModal(); + }, + }); + + useEffect(() => { + if (!activeOrg?.id) return; + + getTelegramConfigForOrg({ + variables: { + orgId: activeOrg?.id, + }, + }); + }, [activeOrg?.id]); const handleSubmit = () => { - console.log('SUBMIT') + validateTelegramGroupId(groupId).then((isValid) => { + if (isValid) { + connectTelegram({ variables: { chatId: `${groupId}`, orgId: activeOrg?.id } }); + } else { + setError("Invalid Group ID"); + } + }); }; const TgComponent = () => { - const handleChange = (e) => setGroupId(e.target.value); + const handleChange = (e) => { + if (error) setError(""); + setGroupId(e.target.value); + }; + + const botLink = getTelegramBotLink(); const config = [ { label: "Link WonderBot", component: () => ( - - Add Bot - - + + + Add Bot + + + ), }, { label: "Group ID", - component: () => , + component: () => , }, ]; + if (!isTelegramModalOpen) return null; + return ( @@ -62,14 +125,20 @@ const useTelegramModal = () => { ); })} + {error ? {error} : null} - Connect + + Connect + ); }; const ConnectButton = () => { + if (data?.getTelegramConfigForOrg?.chatId && !isTelegramModalOpen) { + return Update; + } if (isTelegramModalOpen) { return ( diff --git a/wondrous-bot-admin/src/graphql/mutations/index.ts b/wondrous-bot-admin/src/graphql/mutations/index.ts index bb7d03fe3e..e6f73fab48 100644 --- a/wondrous-bot-admin/src/graphql/mutations/index.ts +++ b/wondrous-bot-admin/src/graphql/mutations/index.ts @@ -1,4 +1,5 @@ export * from './user' export * from './wallet' export * from './quest'; -export * from './org'; \ No newline at end of file +export * from './org'; +export * from './telegram'; \ No newline at end of file diff --git a/wondrous-bot-admin/src/graphql/mutations/telegram.ts b/wondrous-bot-admin/src/graphql/mutations/telegram.ts new file mode 100644 index 0000000000..51162e56c9 --- /dev/null +++ b/wondrous-bot-admin/src/graphql/mutations/telegram.ts @@ -0,0 +1,10 @@ +import { gql } from "@apollo/client"; + +export const CONNECT_TELEGRAM_BOT = gql` + mutation connectCommunitiesBot($orgId: ID, $chatId: String) { + connectCommunitiesBot(orgId: $orgId, chatId: $chatId) { + success + } + } +`; + diff --git a/wondrous-bot-admin/src/graphql/queries/telegram.ts b/wondrous-bot-admin/src/graphql/queries/telegram.ts new file mode 100644 index 0000000000..85578c309f --- /dev/null +++ b/wondrous-bot-admin/src/graphql/queries/telegram.ts @@ -0,0 +1,10 @@ +import { gql } from "@apollo/client"; + +export const GET_TELEGRAM_CONFIG_FOR_ORG = gql` + query getTelegramConfigForOrg($orgId: ID) { + getTelegramConfigForOrg(orgId: $orgId) { + chatId + orgId + } + } +`; \ No newline at end of file diff --git a/wondrous-bot-admin/src/utils/discord/index.tsx b/wondrous-bot-admin/src/utils/discord/index.tsx index d05ce9bcdc..53fce38fa5 100644 --- a/wondrous-bot-admin/src/utils/discord/index.tsx +++ b/wondrous-bot-admin/src/utils/discord/index.tsx @@ -81,11 +81,13 @@ export const getDiscordUrl = (callbackUrl = '/discord/callback', params = '') => return `https://discord.com/api/oauth2/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=email%20identify${params}`; }; + + export const getTelegramBotLink = () => { if (import.meta.env.VITE_PRODUCTION) { - return "https://t.me/wonderverse_bot"; + return "https://t.me/communities_test_bot?startgroup=true&admin=post_messages"; } - return "https://t.me/wonderverse_staging_bot"; + return "https://t.me/communities_test_bot?startgroup=true&admin=post_messages"; }; export const useDiscordRoles = ({ orgId, skip = false }) => { From c3ad996b52c189c6b487f4141603a71b66a144c5 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Thu, 10 Aug 2023 19:10:37 +0300 Subject: [PATCH 04/31] tg integration --- .../components/ConnectBotComponent/index.tsx | 80 +++++++++---------- .../src/components/Icons/Discord.tsx | 4 +- .../src/components/Icons/Telegram.tsx | 4 +- .../Settings/NotificationSettings/styles.tsx | 2 +- .../discord/callback/org-connect/index.tsx | 1 + wondrous-bot-admin/src/pages/home.tsx | 28 +++++-- .../pages/onboarding/discord/addBotModal.tsx | 15 ++-- .../src/pages/settings/connect.tsx | 19 ++++- .../src/utils/discord/index.tsx | 8 +- 9 files changed, 95 insertions(+), 66 deletions(-) diff --git a/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx b/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx index 87604fe53e..784dd21c6f 100644 --- a/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx +++ b/wondrous-bot-admin/src/components/ConnectBotComponent/index.tsx @@ -1,13 +1,12 @@ import { Box, ButtonBase, Grid, Typography } from "@mui/material"; import { getDiscordBotOauthURL } from "components/ConnectDiscord/ConnectDiscordButton"; -import { GreenBgDiscord } from "components/Icons/Discord"; -import { TelegramGreenBg } from "components/Icons/Telegram"; +import { ConnectDiscordIcon } from "components/Icons/Discord"; +import { TelegramConnectIcon } from "components/Icons/Telegram"; import { NotificationWrapper } from "components/Settings/NotificationSettings/styles"; import { ErrorText, SharedSecondaryButton } from "components/Shared/styles"; import { useContext, useEffect, useState } from "react"; import GlobalContext from "utils/context/GlobalContext"; import { AddBotLink, SharedLabel, StatusPill } from "./styles"; -import OpenInNewIcon from "@mui/icons-material/OpenInNew"; import { ExternalLinkIcon } from "components/Icons/ExternalLink"; import { CustomTextField } from "components/AddFormEntity/components/styles"; import { getTelegramBotLink } from "utils/discord"; @@ -153,13 +152,14 @@ const useTelegramModal = () => { return { TgComponent, ConnectButton, + isConnected: data?.getTelegramConfigForOrg?.chatId, }; }; -const ConnectBotComponent = () => { +const ConnectBotComponent = ({ cardBgColor = "white" }) => { const { activeOrg } = useContext(GlobalContext); const oauthUrl = getDiscordBotOauthURL({ orgId: activeOrg?.id }); - const { TgComponent, ConnectButton } = useTelegramModal(); + const { TgComponent, ConnectButton, isConnected: isTelegramConnected } = useTelegramModal(); const handleDiscordClick = async () => { window.location.href = oauthUrl; }; @@ -167,56 +167,48 @@ const ConnectBotComponent = () => { const CARDS_CONFIG = [ { title: "Discord", - icon: GreenBgDiscord, + icon: ConnectDiscordIcon, onClick: handleDiscordClick, isConnected: !!activeOrg?.cmtyDiscordConfig, + iconProps: { + fill: !!activeOrg?.cmtyDiscordConfig ? "#AF9EFF" : "#2A8D5C", + }, }, { title: "Telegram", - icon: TelegramGreenBg, + icon: TelegramConnectIcon, + iconProps: { + fill: isTelegramConnected ? "#AF9EFF" : "#2A8D5C", + }, component: TgComponent, customButton: ConnectButton, }, ]; return ( - - You can connect your bot to either or both platforms below. - - {CARDS_CONFIG.map((card) => ( - - - - {card.title} - - {card.customButton ? ( - card.customButton() - ) : ( - <> - {card.isConnected ? ( - Connected - ) : ( - Connect - )} - - )} - - - {card.component && <>{card.component()}} - - ))} - + + {CARDS_CONFIG.map((card) => ( + + + + {card.title} + + {card.customButton ? ( + card.customButton() + ) : ( + <> + {card.isConnected ? ( + Connected + ) : ( + Connect + )} + + )} + + + {card.component && <>{card.component()}} + + ))} ); }; diff --git a/wondrous-bot-admin/src/components/Icons/Discord.tsx b/wondrous-bot-admin/src/components/Icons/Discord.tsx index ab8abdfaba..1f1827ca5c 100644 --- a/wondrous-bot-admin/src/components/Icons/Discord.tsx +++ b/wondrous-bot-admin/src/components/Icons/Discord.tsx @@ -19,9 +19,9 @@ export const ShapedHexagonWrapper = () => ( ); -export const GreenBgDiscord = () => ( +export const ConnectDiscordIcon = ({fill = "#2A8D5C"}) => ( - + ( +export const TelegramConnectIcon = ({fill = "#2A8D5C"}) => ( - + bgColor}; flex-direction: column; align-items: flex-start; align-self: stretch; diff --git a/wondrous-bot-admin/src/pages/discord/callback/org-connect/index.tsx b/wondrous-bot-admin/src/pages/discord/callback/org-connect/index.tsx index 69acdf0c6f..1cd007f6ae 100644 --- a/wondrous-bot-admin/src/pages/discord/callback/org-connect/index.tsx +++ b/wondrous-bot-admin/src/pages/discord/callback/org-connect/index.tsx @@ -22,6 +22,7 @@ const CallbackPage = () => { } navigate("/"); }, + refetchQueries: ['getLoggedInUserFullAccessOrgs'], onError: (e) => { console.error("error connecting discord", e); setErrorText("Error connecting discord - please try again"); diff --git a/wondrous-bot-admin/src/pages/home.tsx b/wondrous-bot-admin/src/pages/home.tsx index 74c0bf83cf..215166b79e 100644 --- a/wondrous-bot-admin/src/pages/home.tsx +++ b/wondrous-bot-admin/src/pages/home.tsx @@ -17,6 +17,7 @@ import { AddBotModal } from "pages/onboarding/discord/addBotModal"; import { ConfigureNotificationsOnboardingModal } from "./onboarding/discord/configureNotificationsModal"; import { usePaywall, useSubscription } from "utils/hooks"; import { PricingOptionsTitle, getPlan } from "components/Pricing/PricingOptionsListItem"; +import { GET_TELEGRAM_CONFIG_FOR_ORG } from "graphql/queries/telegram"; const typographyStyles = { fontFamily: "Poppins", @@ -83,9 +84,16 @@ const HomePage = () => { const { setPaywall, setPaywallMessage } = usePaywall(); const plan = getPlan(subscription?.tier); const navigate = useNavigate(); - const [openDiscordModal, setOpenDiscordModal] = useState(false); + const [openAddBotModal, setOpenAddBotModal] = useState(false); const [openDiscordNotificationModal, setOpenDiscordNotificationModal] = useState(false); const { setIsOpen, setCurrentStep } = useTour(); + const { data: telegramConfigData } = useQuery(GET_TELEGRAM_CONFIG_FOR_ORG, { + variables: { + orgId: activeOrg?.id, + }, + notifyOnNetworkStatusChange: true, + skip: !activeOrg?.id, + }); const { data: orgDiscordConfig, error: getDiscordConfigError } = useQuery(GET_CMTY_ORG_DISCORD_CONFIG, { notifyOnNetworkStatusChange: true, variables: { @@ -93,6 +101,7 @@ const HomePage = () => { }, skip: !activeOrg?.id, }); + const additionalData = orgDiscordConfig?.getCmtyOrgDiscordConfig?.additionalData; const discordNotConfigured = getDiscordConfigError?.graphQLErrors[0]?.message === "Not"; const { data, loading } = useQuery(GET_ORG_QUEST_STATS, { @@ -137,19 +146,28 @@ const HomePage = () => { navigate("/quests/create"); } }; + useEffect(() => { - if (getDiscordConfigError?.graphQLErrors[0]?.message && !loading) { - setOpenDiscordModal(true); + if ( + (getDiscordConfigError?.graphQLErrors[0]?.message && !loading) || + !telegramConfigData?.getTelegramConfigForOrg?.chatId + ) { + setOpenAddBotModal(true); } - }, [getDiscordConfigError?.graphQLErrors[0]?.message, loading]); + }, [getDiscordConfigError?.graphQLErrors[0]?.message, loading, telegramConfigData?.getTelegramConfigForOrg?.chatId]); useEffect(() => { if (!loading && orgDiscordConfig?.getCmtyOrgDiscordConfige && !additionalData) [setOpenDiscordNotificationModal(true)]; }, [additionalData, orgDiscordConfig?.getCmtyOrgDiscordConfig, loading]); + + const isAddModalOpen = + openAddBotModal && + (!telegramConfigData?.getTelegramConfigForOrg?.chatId || !orgDiscordConfig?.getCmtyOrgDiscordConfig?.id); + return ( - setOpenDiscordModal(false)} orgId={activeOrg?.id} /> + setOpenAddBotModal(false)} /> setOpenDiscordNotificationModal(false)} diff --git a/wondrous-bot-admin/src/pages/onboarding/discord/addBotModal.tsx b/wondrous-bot-admin/src/pages/onboarding/discord/addBotModal.tsx index 171b03d5d1..1c321a8e64 100644 --- a/wondrous-bot-admin/src/pages/onboarding/discord/addBotModal.tsx +++ b/wondrous-bot-admin/src/pages/onboarding/discord/addBotModal.tsx @@ -3,23 +3,18 @@ import { ConnectWonderbotDescription, ConnectWonderbotImg, ConnectWonderbotText import AddDiscordImg from "assets/addDiscord.svg"; import { SharedSecondaryButton } from "components/Shared/styles"; import { Box } from "@mui/material"; -import { getDiscordBotOauthURL } from "components/ConnectDiscord/ConnectDiscordButton"; +import ConnectBotComponent from "components/ConnectBotComponent"; -export const AddBotModal = ({ open, onClose, orgId }) => { - const oauthUrl = getDiscordBotOauthURL({ orgId }); - - const handleClick = async () => { - window.location.href = oauthUrl; - }; +export const AddBotModal = ({ open, onClose }) => { return ( Connect the WonderBot - Connect WonderBot to your Discord server for free. Trusted by top servers with no risk to your community. + The party doesn't start until you add WonderBot to your server! Connect WonderBot to your server to start + sending out quests.{" "} - - Connect Bot + { }} > - + + You can connect your bot to either or both platforms below. + + + ); diff --git a/wondrous-bot-admin/src/utils/discord/index.tsx b/wondrous-bot-admin/src/utils/discord/index.tsx index 53fce38fa5..0bda549098 100644 --- a/wondrous-bot-admin/src/utils/discord/index.tsx +++ b/wondrous-bot-admin/src/utils/discord/index.tsx @@ -84,8 +84,14 @@ export const getDiscordUrl = (callbackUrl = '/discord/callback', params = '') => export const getTelegramBotLink = () => { + let botName = 'wonder_communities_bot' + let link = `https://t.me/${botName}?startgroup=true&admin=post_messages`; if (import.meta.env.VITE_PRODUCTION) { - return "https://t.me/communities_test_bot?startgroup=true&admin=post_messages"; + return link; + } + if(import.meta.env.VITE_STAGING) { + botName = 'communities_staging_bot' + return link; } return "https://t.me/communities_test_bot?startgroup=true&admin=post_messages"; }; From f8527b0cb1fdc1131b689585f9a5955d8d8577ad Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Thu, 10 Aug 2023 19:16:31 +0300 Subject: [PATCH 05/31] remove unused stuff --- wondrous-bot-admin/index.html | 1 - wondrous-bot-admin/src/App.tsx | 5 -- wondrous-bot-admin/src/main.tsx | 2 +- .../src/pages/telegram/index.tsx | 47 ------------------- wondrous-bot-admin/src/utils/constants.tsx | 2 - 5 files changed, 1 insertion(+), 56 deletions(-) delete mode 100644 wondrous-bot-admin/src/pages/telegram/index.tsx diff --git a/wondrous-bot-admin/index.html b/wondrous-bot-admin/index.html index b9dcf6bc86..d2f940a0f8 100644 --- a/wondrous-bot-admin/index.html +++ b/wondrous-bot-admin/index.html @@ -5,7 +5,6 @@ - }, - { - path: '/telegram', - element: - } ], }, ]); diff --git a/wondrous-bot-admin/src/main.tsx b/wondrous-bot-admin/src/main.tsx index 1c3d805501..ba8922c13a 100644 --- a/wondrous-bot-admin/src/main.tsx +++ b/wondrous-bot-admin/src/main.tsx @@ -7,7 +7,7 @@ declare global { if (typeof window !== "undefined") { window.global = window; - // window.Buffer = Buffer; + window.Buffer = Buffer; } import React from "react"; import ReactDOM from "react-dom/client"; diff --git a/wondrous-bot-admin/src/pages/telegram/index.tsx b/wondrous-bot-admin/src/pages/telegram/index.tsx deleted file mode 100644 index b4ea9982eb..0000000000 --- a/wondrous-bot-admin/src/pages/telegram/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React, { useEffect } from "react"; - -const TelegramPage = () => { - let tg = (window as any).Telegram.WebApp; - - useEffect(() => { - // Define the onTelegramAuth function on the global scope - (window as any).onTelegramAuth = (user) => { - console.log(user, 'UUUUSER') - alert( - "Logged in as " + - user.first_name + - " " + - user.last_name + - " (" + - user.id + - (user.username ? ", @" + user.username : "") + - ")" - ); - }; - - // Create and append the script tag - const script = document.createElement("script"); - script.async = true; - script.src = "https://telegram.org/js/telegram-widget.js?22"; - script.setAttribute("data-telegram-login", "communities_test_bot"); - script.setAttribute("data-size", "large"); - script.setAttribute("data-onauth", "onTelegramAuth(user)"); - script.setAttribute("data-request-access", "write"); - document.body.appendChild(script); - - // Cleanup: remove script when component unmounts - return () => { - document.body.removeChild(script); - }; - }, []); - - tg.expand(); - - return ( -
-

{JSON.stringify(tg)}

-
- ); -}; - -export default TelegramPage; diff --git a/wondrous-bot-admin/src/utils/constants.tsx b/wondrous-bot-admin/src/utils/constants.tsx index 6b232d0e22..62f70708e0 100644 --- a/wondrous-bot-admin/src/utils/constants.tsx +++ b/wondrous-bot-admin/src/utils/constants.tsx @@ -99,7 +99,6 @@ export const PAGES_WITHOUT_HEADER = [ "/discord/callback/cmty-user-connect", "/invite/:token", "/verify-link", - '/telegram' ]; export const BG_TYPES = { @@ -307,7 +306,6 @@ export const EXCLUDED_PATHS = [ "/invite/:token", "/verify-link", "/wallet/connect", - "/telegram" ]; export const TUTORIALS = { From b788b76327fa95ae825b826e19c975829d4b8a17 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Fri, 11 Aug 2023 09:40:57 +0300 Subject: [PATCH 06/31] update tg integration --- .../Helpers/TelegramIntegrationFooter.tsx | 43 ++++++- .../Integrations/TelegramIntegration.tsx | 111 +++++++----------- .../Settings/Integrations/styles.tsx | 10 ++ wondrous-app/graphql/mutations/integration.ts | 8 +- wondrous-app/utils/index.ts | 4 +- .../src/graphql/mutations/telegram.ts | 4 +- 6 files changed, 101 insertions(+), 79 deletions(-) diff --git a/wondrous-app/components/Settings/Integrations/Helpers/TelegramIntegrationFooter.tsx b/wondrous-app/components/Settings/Integrations/Helpers/TelegramIntegrationFooter.tsx index 6586a3fae0..bbcd8ee3b7 100644 --- a/wondrous-app/components/Settings/Integrations/Helpers/TelegramIntegrationFooter.tsx +++ b/wondrous-app/components/Settings/Integrations/Helpers/TelegramIntegrationFooter.tsx @@ -1,13 +1,46 @@ import { useContext } from 'react'; import { getTelegramBotLink } from 'utils/index'; -import ConnectionContext from './ConnectionContext'; +import * as yup from 'yup'; +import { CONNECT_TELEGRAM_BOT } from 'graphql/mutations'; +import { useMutation } from '@apollo/client'; import FooterButtons from './FooterButtons'; +import ConnectionContext from './ConnectionContext'; + +const telegramGroupIdSchema = yup + .number() + .integer('ID must be an integer.') + .negative('ID must be negative.') + .required('ID is required.'); + +const validateTelegramGroupId = async (groupId) => { + try { + await telegramGroupIdSchema.validate(groupId); + return true; + } catch (error) { + console.error(error.message); + return false; + } +}; const TelegramIntegrationFooter = () => { - const { onClose, data } = useContext(ConnectionContext); - const tgLink = getTelegramBotLink(); - const handleOnClick = () => window.open(tgLink, '_blank'); - return ; + const [connectTelegram] = useMutation(CONNECT_TELEGRAM_BOT, { + refetchQueries: ['getOrgIntegrations', 'getPodIntegrations'], + }); + + const { onClose, data, setData, orgId, podId } = useContext(ConnectionContext); + const handleConnect = () => { + const { tgValue } = data; + validateTelegramGroupId(tgValue).then((isValid) => { + if (isValid) { + connectTelegram({ variables: { chatId: `${tgValue}`, orgId, podId } }); + onClose(); + } else { + setData((prev) => ({ ...prev, tgError: 'Invalid Group ID' })); + } + }); + }; + + return ; }; export default TelegramIntegrationFooter; diff --git a/wondrous-app/components/Settings/Integrations/TelegramIntegration.tsx b/wondrous-app/components/Settings/Integrations/TelegramIntegration.tsx index dedc4fd6c2..3487558d98 100644 --- a/wondrous-app/components/Settings/Integrations/TelegramIntegration.tsx +++ b/wondrous-app/components/Settings/Integrations/TelegramIntegration.tsx @@ -1,88 +1,65 @@ -import { Grid, Typography } from '@mui/material'; +import { Box, Grid, Typography } from '@mui/material'; import GradientHeading from 'components/GradientHeading'; import { UnstyledLink } from 'components/WorkspacePicker/styles'; import { NewTabIcon } from 'components/Icons/taskModalIcons'; import palette from 'theme/palette'; import { CopyContainer, CopyTypography } from 'components/Common/InviteLinkModal/styles'; import CopyIcon from 'components/Icons/copy'; -import { useContext, useEffect, useState } from 'react'; +import { useContext, useEffect, useRef, useState } from 'react'; import { useMutation } from '@apollo/client'; -import { CONNECT_TELEGRAM } from 'graphql/mutations'; +import { CONNECT_TELEGRAM_BOT } from 'graphql/mutations'; import { getTelegramBotLink } from 'utils/index'; -import { TelegramBotInfo, TelegramLabel } from './styles'; +import { ErrorText } from 'components/Common'; +import { GroupInput, TelegramBotInfo, TelegramLabel } from './styles'; import ConnectionContext from './Helpers/ConnectionContext'; const TelegramIntegration = () => { - const { orgId, podId } = useContext(ConnectionContext); - - const [copied, setCopied] = useState(false); - - const [connectTelegram, { data }] = useMutation(CONNECT_TELEGRAM, { - variables: { - orgId, - podId, - }, - }); - - const token = `token:${data?.connectTelegram}`; - - useEffect(() => { - if (orgId) { - connectTelegram(); - } - }, [orgId, podId]); - - const handleOnCopy = () => { - navigator.clipboard.writeText(`${token}`); - setCopied(true); - }; + const { data, setData } = useContext(ConnectionContext); + const { tgError } = data; const tgLink = getTelegramBotLink(); return ( Setup instructions - Step 1 speak to our bot - - - @wonderverse_bot - - - - Step 2 - - - {token} - - - - {copied ? 'Code copied' : 'Copy code'} - + + + Link WonderBot + + + @wonderverse_bot + + + + + + Group ID + + + setData((prev) => ({ ...prev, tgValue: e.target.value }))} /> + + + + {tgError ? {tgError} : null} ); }; diff --git a/wondrous-app/components/Settings/Integrations/styles.tsx b/wondrous-app/components/Settings/Integrations/styles.tsx index a396f52ac2..6577c25407 100644 --- a/wondrous-app/components/Settings/Integrations/styles.tsx +++ b/wondrous-app/components/Settings/Integrations/styles.tsx @@ -218,3 +218,13 @@ export const TelegramBotInfo = styled(Typography)` line-height: 17px; } `; + +export const GroupInput = styled(InputBase)` + && { + color: ${palette.white}; + font-family: ${typography.fontFamily}; + font-weight: 400; + font-size: 13px; + line-height: 17px; + } +`; diff --git a/wondrous-app/graphql/mutations/integration.ts b/wondrous-app/graphql/mutations/integration.ts index 965ad0e5c2..f3d913ddba 100644 --- a/wondrous-app/graphql/mutations/integration.ts +++ b/wondrous-app/graphql/mutations/integration.ts @@ -162,9 +162,11 @@ export const CONNECT_COORDINAPE_TO_ORG = gql` } `; -export const CONNECT_TELEGRAM = gql` - mutation connectTelegram($orgId: ID, $podId: ID) { - connectTelegram(orgId: $orgId, podId: $podId) +export const CONNECT_TELEGRAM_BOT = gql` + mutation connectTelegram($orgId: ID, $chatId: String, $podId: ID) { + connectTelegram(orgId: $orgId, chatId: $chatId, podId: $podId) { + success + } } `; diff --git a/wondrous-app/utils/index.ts b/wondrous-app/utils/index.ts index a9935ef4f6..9f798a5425 100644 --- a/wondrous-app/utils/index.ts +++ b/wondrous-app/utils/index.ts @@ -91,7 +91,7 @@ export const getBoardType = ({ orgBoard, podBoard, userBoard }) => { export const getTelegramBotLink = () => { if (process.env.NEXT_PUBLIC_PRODUCTION) { - return 'https://t.me/wonderverse_bot'; + return 'https://t.me/wonderverse_bot?startgroup=true&admin=post_messages'; } - return 'https://t.me/wonderverse_staging_bot'; + return 'https://t.me/wonderverse_test_bot?startgroup=true&admin=post_messages'; }; diff --git a/wondrous-bot-admin/src/graphql/mutations/telegram.ts b/wondrous-bot-admin/src/graphql/mutations/telegram.ts index 51162e56c9..05269bc1d2 100644 --- a/wondrous-bot-admin/src/graphql/mutations/telegram.ts +++ b/wondrous-bot-admin/src/graphql/mutations/telegram.ts @@ -1,8 +1,8 @@ import { gql } from "@apollo/client"; export const CONNECT_TELEGRAM_BOT = gql` - mutation connectCommunitiesBot($orgId: ID, $chatId: String) { - connectCommunitiesBot(orgId: $orgId, chatId: $chatId) { + mutation connectTelegram($orgId: ID, $chatId: String, $podId: ID) { + connectTelegram(orgId: $orgId, chatId: $chatId, podId: $podId) { success } } From a4e3f2a82c484aabee86eceb6901a8d5c2dfaca9 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Thu, 17 Aug 2023 16:20:58 +0300 Subject: [PATCH 07/31] fix media --- wondrous-bot-admin/src/utils/media/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wondrous-bot-admin/src/utils/media/index.tsx b/wondrous-bot-admin/src/utils/media/index.tsx index 8ea5f83eef..8f81f10680 100644 --- a/wondrous-bot-admin/src/utils/media/index.tsx +++ b/wondrous-bot-admin/src/utils/media/index.tsx @@ -99,14 +99,14 @@ export const transformMediaFormat = (media) => })); export function isImage(url, mediaType) { - if (mediaType.includes('image')) { + if (mediaType?.includes('image')) { return true; } return /\.(jpg|jpeg|png|webp|avif|gif|svg)$/.test(url); } export function isVideo(url, mediaType) { - if (mediaType.includes('video')) { + if (mediaType?.includes('video')) { return true; } return /\.(mp4|mov|avi|wmv|flv|webm|mkv|m4v)$/.test(url); From c165a2a3d86c2cdbf363bafebee6046ae342f869 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Fri, 18 Aug 2023 16:26:04 +0300 Subject: [PATCH 08/31] yt telegram, wallet telegram --- .../src/components/Auth/index.tsx | 4 +- .../src/graphql/mutations/user.ts | 4 +- .../src/pages/oauth/google/callback.tsx | 14 +- .../src/pages/wallet/connect/index.tsx | 262 ++++++++---------- 4 files changed, 129 insertions(+), 155 deletions(-) diff --git a/wondrous-bot-admin/src/components/Auth/index.tsx b/wondrous-bot-admin/src/components/Auth/index.tsx index 046feb0107..0fea93eec8 100644 --- a/wondrous-bot-admin/src/components/Auth/index.tsx +++ b/wondrous-bot-admin/src/components/Auth/index.tsx @@ -198,7 +198,8 @@ export const linkCmtyUserWallet = async ( web3Address: string, signedMessage: string, blockchain: string, - originalMessage: string + originalMessage: string, + telegramUserId?: string ) => { try { const { @@ -212,6 +213,7 @@ export const linkCmtyUserWallet = async ( signedMessage, blockchain, originalMessage, + telegramUserId }, }, }); diff --git a/wondrous-bot-admin/src/graphql/mutations/user.ts b/wondrous-bot-admin/src/graphql/mutations/user.ts index 9f1ee3a4b2..f09e3f6844 100644 --- a/wondrous-bot-admin/src/graphql/mutations/user.ts +++ b/wondrous-bot-admin/src/graphql/mutations/user.ts @@ -163,8 +163,8 @@ export const CONNECT_COMMUNITY_USER_WALLET = gql` `; export const CONNECT_COMMUNITY_USER_GOOGLE = gql` - mutation connectCommunityUserGoogle($code: String, $discordId: String) { - connectCommunityUserGoogle(code: $code, discordId: $discordId) { + mutation connectCommunityUserGoogle($code: String, $discordId: String, $telegramUserId: String) { + connectCommunityUserGoogle(code: $code, discordId: $discordId, telegramUserId: $telegramUserId) { success } } diff --git a/wondrous-bot-admin/src/pages/oauth/google/callback.tsx b/wondrous-bot-admin/src/pages/oauth/google/callback.tsx index 70e26a117f..54489189a8 100644 --- a/wondrous-bot-admin/src/pages/oauth/google/callback.tsx +++ b/wondrous-bot-admin/src/pages/oauth/google/callback.tsx @@ -29,8 +29,7 @@ const GoogleOauthCallbackPage = () => { const [searchParams] = useSearchParams(); const code = searchParams?.get("code"); const state = searchParams?.get("state"); - const { discordId } = JSON.parse(state || "{}"); - + const { discordId, telegramUserId } = JSON.parse(state || "{}"); const [finishedVerification, setFinishedVerification] = useState(false); const [errorText, setErrorText] = useState(""); @@ -47,24 +46,25 @@ const GoogleOauthCallbackPage = () => { }); useEffect(() => { - if (code && discordId && !finishedVerification) { + if (code && (discordId || telegramUserId) && !finishedVerification) { setFinishedVerification(true); - connectCommunityUserGoogle({ + connectCommunityUserGoogle({ variables: { code, discordId, + telegramUserId: telegramUserId?.toString(), }, }); } - }, [discordId, code]); - console.log(code) + }, [discordId, code, telegramUserId]); return ( {finishedVerification && ( - Finished connecting your Google account! You can close this window now and return to Discord. + Finished connecting your Google account! You can close this window now and return to{" "} + {telegramUserId ? "Telegram" : "Discord"}. )} {!finishedVerification && ( diff --git a/wondrous-bot-admin/src/pages/wallet/connect/index.tsx b/wondrous-bot-admin/src/pages/wallet/connect/index.tsx index 7035941dbe..ea4286060e 100644 --- a/wondrous-bot-admin/src/pages/wallet/connect/index.tsx +++ b/wondrous-bot-admin/src/pages/wallet/connect/index.tsx @@ -1,157 +1,129 @@ -import { useMutation } from "@apollo/client" -import { CircularProgress, Typography } from "@mui/material" -import Grid from "@mui/material/Grid" -import { - CONNECT_COMMUNITY_USER_WALLET, - VERIFY_COMMUNITY_USER_TWITTER -} from "graphql/mutations" -import { useCallback, useEffect, useState } from "react" -import { useSearchParams } from "react-router-dom" -import { Button } from "./styles" -import { - CoinbaseConnector, - MetaMaskConnector, - WalletConnectConnector -} from "components/Connectors" -import useWonderWeb3 from "services/web3/useWonderWeb3" -import { SupportedChainType, signedMessageIsString } from "utils/web3Constants" -import apollo from "services/apollo" -import { linkCmtyUserWallet } from "components/Auth" -import { GRAPHQL_ERRORS } from "utils/constants" +import { useMutation } from "@apollo/client"; +import { CircularProgress, Typography } from "@mui/material"; +import Grid from "@mui/material/Grid"; +import { CONNECT_COMMUNITY_USER_WALLET, VERIFY_COMMUNITY_USER_TWITTER } from "graphql/mutations"; +import { useCallback, useEffect, useState } from "react"; +import { useSearchParams } from "react-router-dom"; +import { Button } from "./styles"; +import { CoinbaseConnector, MetaMaskConnector, WalletConnectConnector } from "components/Connectors"; +import useWonderWeb3 from "services/web3/useWonderWeb3"; +import { SupportedChainType, signedMessageIsString } from "utils/web3Constants"; +import apollo from "services/apollo"; +import { linkCmtyUserWallet } from "components/Auth"; +import { GRAPHQL_ERRORS } from "utils/constants"; const buttonStyles = { - marginRight: "8px" -} + marginRight: "8px", +}; function getFormattedDate() { - var date = new Date(); - var str = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds(); + var date = new Date(); + var str = + date.getFullYear() + + "-" + + (date.getMonth() + 1) + + "-" + + date.getDate() + + " " + + date.getHours() + + ":" + + date.getMinutes() + + ":" + + date.getSeconds(); - return str; + return str; } const WalletConnectPage = () => { - const [searchParams] = useSearchParams() - const wonderWeb3 = useWonderWeb3() - const discordUserId = searchParams?.get("discordUserId") - const [errorMessage, setErrorMessage] = useState(null) - const [connectionComplete, setConnectionComplete] = useState(false) + const [searchParams] = useSearchParams(); + const wonderWeb3 = useWonderWeb3(); + const discordUserId = searchParams?.get("discordUserId"); + const telegramUserId = searchParams?.get("telegramUserId"); + const [errorMessage, setErrorMessage] = useState(null); + const [connectionComplete, setConnectionComplete] = useState(false); - const linkUserWithWallet = useCallback(async () => { - if (wonderWeb3.address && wonderWeb3.chain && !wonderWeb3.connecting) { - // get current timestamp - const timestamp = Date.now().toString() + const linkUserWithWallet = useCallback(async () => { + if (wonderWeb3.address && wonderWeb3.chain && !wonderWeb3.connecting) { + // get current timestamp + const timestamp = Date.now().toString(); - const messageToSign = `Welcome to wonder\nDate: ${getFormattedDate()}\nTimestamp: ${Date.now().toString()}` - if (messageToSign) { - const signedMessage = await wonderWeb3.signMessage(messageToSign) - if (signedMessageIsString(signedMessage)) { - const result = await linkCmtyUserWallet( - discordUserId, - wonderWeb3.address, - signedMessage, - SupportedChainType.ETH, - messageToSign - ) - if (result === true) { - setConnectionComplete(true) - } - if (result === false) { - setErrorMessage("Error linking wallet, please contact support") - wonderWeb3.disconnect() - } - } else if (signedMessage === false) { - setErrorMessage("Signature rejected. Try again.") - wonderWeb3.disconnect() - } - } - } - }, [wonderWeb3]) + const messageToSign = `Welcome to wonder\nDate: ${getFormattedDate()}\nTimestamp: ${Date.now().toString()}`; + if (messageToSign) { + const signedMessage = await wonderWeb3.signMessage(messageToSign); + if (signedMessageIsString(signedMessage)) { + const result = await linkCmtyUserWallet( + discordUserId, + wonderWeb3.address, + signedMessage, + SupportedChainType.ETH, + messageToSign, + telegramUserId + ); + if (result === true) { + setConnectionComplete(true); + } + if (result === false) { + setErrorMessage("Error linking wallet, please contact support"); + wonderWeb3.disconnect(); + } + } else if (signedMessage === false) { + setErrorMessage("Signature rejected. Try again."); + wonderWeb3.disconnect(); + } + } + } + }, [wonderWeb3]); - useEffect(() => { - if (wonderWeb3.address && wonderWeb3.active && wonderWeb3.web3Provider) { - linkUserWithWallet() - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [wonderWeb3.wallet, wonderWeb3.active, wonderWeb3.web3Provider]) - return ( - - - {!connectionComplete ? ( - <> - - Connect your wallet via the providers below - -
- - - -
- {errorMessage && ( - - {errorMessage} - - )} - - ) : ( - <> - - You're all set! Please close the page and return to Discord - - - )} -
- -
- ) -} + useEffect(() => { + if (wonderWeb3.address && wonderWeb3.active && wonderWeb3.web3Provider) { + linkUserWithWallet(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [wonderWeb3.wallet, wonderWeb3.active, wonderWeb3.web3Provider]); + return ( + + + {!connectionComplete ? ( + <> + + Connect your wallet via the providers below + +
+ + + +
+ {errorMessage && ( + + {errorMessage} + + )} + + ) : ( + <> + + You're all set! Please close the page and return to {telegramUserId ? 'Telegram' : "Discord"} + + + )} +
+ +
+ ); +}; -export default WalletConnectPage +export default WalletConnectPage; From c150ab2712309f12fcb49bc3c3341a06659ef62c Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Wed, 23 Aug 2023 12:15:14 +0300 Subject: [PATCH 09/31] wips --- wondrous-bot-admin/src/App.tsx | 17 +- .../AddFormEntity/components/styles.tsx | 2 +- .../src/components/QuestSteps/Steps/Text.tsx | 15 ++ .../src/components/QuestSteps/Steps/index.tsx | 1 + .../src/components/QuestSteps/index.tsx | 61 +++++++ .../src/graphql/queries/quest.ts | 9 + wondrous-bot-admin/src/main.tsx | 2 +- .../src/pages/telegram/start-quest/index.tsx | 159 ++++++++++++++++++ .../src/services/apollo/index.tsx | 8 +- wondrous-bot-admin/src/utils/constants.tsx | 3 + 10 files changed, 268 insertions(+), 9 deletions(-) create mode 100644 wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx create mode 100644 wondrous-bot-admin/src/components/QuestSteps/Steps/index.tsx create mode 100644 wondrous-bot-admin/src/components/QuestSteps/index.tsx create mode 100644 wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx diff --git a/wondrous-bot-admin/src/App.tsx b/wondrous-bot-admin/src/App.tsx index 5a558e53c1..622e48d200 100644 --- a/wondrous-bot-admin/src/App.tsx +++ b/wondrous-bot-admin/src/App.tsx @@ -45,6 +45,7 @@ import AnalyticsPage from "pages/analytics"; import PremiumFeatureDialog from "components/PremiumFeatureDialog"; import PaywallContext from "utils/context/PaywallContext"; import ConnectPage from "pages/settings/connect"; +import TelegramStatQuest from "pages/telegram/start-quest"; const router = createBrowserRouter([ { @@ -75,8 +76,8 @@ const router = createBrowserRouter([ element: , }, { - path: '/settings/connect', - element: + path: "/settings/connect", + element: , }, { path: "/", @@ -159,12 +160,16 @@ const router = createBrowserRouter([ element: , }, { - path: '/verify-link', - element: + path: "/verify-link", + element: , }, { - path: '/analytics', - element: + path: "/analytics", + element: , + }, + { + path: "/telegram/start-quest/:id", + element: , }, ], }, diff --git a/wondrous-bot-admin/src/components/AddFormEntity/components/styles.tsx b/wondrous-bot-admin/src/components/AddFormEntity/components/styles.tsx index 601422f136..2ac757f46e 100644 --- a/wondrous-bot-admin/src/components/AddFormEntity/components/styles.tsx +++ b/wondrous-bot-admin/src/components/AddFormEntity/components/styles.tsx @@ -30,7 +30,7 @@ export const CustomTextField = styled(InputUnstyled)` export const Label = styled(Typography)` && { - color: #4d4d4d; + color: ${({color = '#4d4d4d'}) => color}; font-family: 'Poppins'; font-style: normal; font-weight: 600; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx new file mode 100644 index 0000000000..bdb9e9b631 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx @@ -0,0 +1,15 @@ +import { Grid } from "@mui/material"; +import { Label } from "components/AddFormEntity/components/styles"; +import TextField from "components/Shared/TextField"; + +export const StepTextField = ({ step, onChange, value }) => { + return ( + <> + + + + + + + ); +}; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/index.tsx new file mode 100644 index 0000000000..22e10b6750 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/index.tsx @@ -0,0 +1 @@ +export * from "./Text"; diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx new file mode 100644 index 0000000000..a63e9ae429 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -0,0 +1,61 @@ +import { TYPES } from "utils/constants"; +import { StepTextField } from "./Steps"; +import { Grid } from "@mui/material"; +import PanelComponent from "components/CreateTemplate/PanelComponent"; +import { CampaignOverviewTitle } from "components/CreateTemplate/styles"; +import { useState } from "react"; + +const COMPONENTS_CONFIG: any = { + [TYPES.TEXT_FIELD]: StepTextField, +}; + +const QuestStep = ({ step, onChange, value }) => { + const Component: React.FC = COMPONENTS_CONFIG[step?.type]; + if (Component) { + return ( + ( + + Step {step.order} + + )} + renderBody={() => onChange({ id: step.id, value })} />} + /> + ); + } + return null; +}; + +const QuestStepsList = ({ quest }) => { + const { steps } = quest || []; + const [responses, setResponses] = useState({}); + + console.log(responses, "STEPS"); + + const handleChange = ({ id, value, skip = false }) => + setResponses({ + ...responses, + [id]: skip ? null : value, + }); + + return ( + + {steps?.map((step, idx) => { + return ; + })} + + ); +}; + +export default QuestStepsList; diff --git a/wondrous-bot-admin/src/graphql/queries/quest.ts b/wondrous-bot-admin/src/graphql/queries/quest.ts index 9e708719bc..248952614f 100644 --- a/wondrous-bot-admin/src/graphql/queries/quest.ts +++ b/wondrous-bot-admin/src/graphql/queries/quest.ts @@ -192,3 +192,12 @@ export const GET_POAP_EVENT = gql` } } `; + +export const USER_CAN_START_QUEST = gql` + query userCanStartQuest($telegramUserId: String, $telegramUsername: String, $questId: String) { + userCanStartQuest(telegramUserId: $telegramUserId, telegramUsername: $telegramUsername, questId: $questId) { + canStart + error + } + } +`; diff --git a/wondrous-bot-admin/src/main.tsx b/wondrous-bot-admin/src/main.tsx index ba8922c13a..1c3d805501 100644 --- a/wondrous-bot-admin/src/main.tsx +++ b/wondrous-bot-admin/src/main.tsx @@ -7,7 +7,7 @@ declare global { if (typeof window !== "undefined") { window.global = window; - window.Buffer = Buffer; + // window.Buffer = Buffer; } import React from "react"; import ReactDOM from "react-dom/client"; diff --git a/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx b/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx new file mode 100644 index 0000000000..c87e616aa5 --- /dev/null +++ b/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx @@ -0,0 +1,159 @@ +import { useLazyQuery } from "@apollo/client"; +import PageSpinner from "components/PageSpinner"; +import QuestSteps from "components/QuestSteps"; +import PageWrapper from "components/Shared/PageWrapper"; +import { GET_QUEST_BY_ID, USER_CAN_START_QUEST } from "graphql/queries"; +import { useEffect, useLayoutEffect, useMemo, useState } from "react"; +import { useLocation, useParams } from "react-router-dom"; +import { BG_TYPES } from "utils/constants"; + +export interface ITelegramUser { + id: number; + first_name: string; + last_name: string; + username: string; + language_code: string; +} + +export interface IWebApp { + initData: string; + initDataUnsafe: { + query_id: string; + user: ITelegramUser; + auth_date: string; + hash: string; + }; + version: string; + platform: string; + colorScheme: string; + themeParams: { + link_color: string; + button_color: string; + button_text_color: string; + secondary_bg_color: string; + hint_color: string; + bg_color: string; + text_color: string; + }; + isExpanded: boolean; + viewportHeight: number; + viewportStableHeight: number; + isClosingConfirmationEnabled: boolean; + headerColor: string; + backgroundColor: string; + BackButton: { + isVisible: boolean; + }; + MainButton: { + text: string; + color: string; + textColor: string; + isVisible: boolean; + isProgressVisible: boolean; + isActive: boolean; + }; + HapticFeedback: any; +} + +export const TelegramStartQuest = () => { + const [webApp, setWebApp] = useState(null); + let { id, ...rest } = useParams(); + + const [getQuestById, { data, loading, refetch }] = useLazyQuery(GET_QUEST_BY_ID, { + fetchPolicy: "network-only", + onCompleted: (data) => { + document.title = data?.getQuestById?.title; + }, + }); + + const [canUserStartQuest, { data: canStartData, error: canStartError }] = useLazyQuery(USER_CAN_START_QUEST, { + fetchPolicy: "network-only", + }); + + useLayoutEffect(() => { + const script = document.createElement("script"); + script.src = "https://telegram.org/js/telegram-web-app.js"; + script.async = true; + document.body.appendChild(script); + const app = (window as any).Telegram?.WebApp; + if (app) { + app.ready(); + setWebApp(app); + } + return () => { + document.body.removeChild(script); + }; + }, []); + + const value = { + webApp, + unsafeData: webApp?.initDataUnsafe, + user: webApp?.initDataUnsafe.user, + }; + + const handleStart = async () => { + const { data } = await canUserStartQuest({ + variables: { + questId: id, + telegramUserId: webApp?.initDataUnsafe?.user?.id?.toString(), + telegramUsername: webApp?.initDataUnsafe?.user?.username, + }, + }); + if (data?.userCanStartQuest?.canStart) { + getQuestById({ + variables: { + questId: id, + }, + }); + } + }; + useEffect(() => { + handleStart(); + if (!webApp?.initDataUnsafe?.user?.id) { + return; + } + }, [webApp?.initDataUnsafe?.user?.id, webApp?.initDataUnsafe?.user?.username]); + + const { user, unsafeData } = value; + console.log(data, loading) + return ( + + {data?.getQuestById ? : } + + //
+ // {canStartData ? JSON.stringify(data?.getQuestById) : "NO DATA CAN START"} + // QUEST_ID = {id} + // {user ? ( + //
+ //

Welcome {user?.username}

+ // User data: + //
{JSON.stringify(user, null, 2)}
+ // Enter Web App data: + //
{JSON.stringify(webApp, null, 2)}
+ // UNSAFE DATA + //
{JSON.stringify(unsafeData)}
+ //
+ // ) : ( + //
Make sure web app is opened from telegram client
+ // )} + //
+ ); +}; + +export default TelegramStartQuest; diff --git a/wondrous-bot-admin/src/services/apollo/index.tsx b/wondrous-bot-admin/src/services/apollo/index.tsx index 92f6dca191..35c20bf949 100644 --- a/wondrous-bot-admin/src/services/apollo/index.tsx +++ b/wondrous-bot-admin/src/services/apollo/index.tsx @@ -11,7 +11,13 @@ const graphqlUri = !import.meta.env.VITE_STAGING const httpLink = new HttpLink({ uri: graphqlUri, - credentials: "include", + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', + 'Access-Control-Allow-Headers': 'Origin, Content-Type, Accept, Authorization, X-Request-With', + } + // credentials: "include", + }); const getAuth = () => { diff --git a/wondrous-bot-admin/src/utils/constants.tsx b/wondrous-bot-admin/src/utils/constants.tsx index 62f70708e0..210a18a713 100644 --- a/wondrous-bot-admin/src/utils/constants.tsx +++ b/wondrous-bot-admin/src/utils/constants.tsx @@ -99,6 +99,7 @@ export const PAGES_WITHOUT_HEADER = [ "/discord/callback/cmty-user-connect", "/invite/:token", "/verify-link", + "/telegram/start-quest/:id", ]; export const BG_TYPES = { @@ -306,8 +307,10 @@ export const EXCLUDED_PATHS = [ "/invite/:token", "/verify-link", "/wallet/connect", + "/telegram/start-quest/:id", ]; + export const TUTORIALS = { COMMUNITIES_HOME_GUIDE: "communities_home_guide", COMMUNITIES_QUESTS_PAGE_GUIDE: "communities_quests_page_guide", From 5175044ed24a85faecf26a49662039962b849914 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Fri, 25 Aug 2023 18:54:26 +0300 Subject: [PATCH 10/31] more quest steps --- wondrous-bot-admin/index.html | 5 +- wondrous-bot-admin/src/assets/botIcon.tsx | 122 ++++++++++++++++++ .../src/components/PaymentLedger/styles.tsx | 6 +- .../components/QuestSteps/StepModal/index.tsx | 35 +++++ .../QuestSteps/Steps/Attachment.tsx | 112 ++++++++++++++++ .../QuestSteps/Steps/OptionSelect.tsx | 97 ++++++++++++++ .../src/components/QuestSteps/Steps/Text.tsx | 6 +- .../QuestSteps/Steps/VerifyButton.tsx | 4 + .../src/components/QuestSteps/index.tsx | 67 ++++++++-- .../src/components/Shared/FileUpload.tsx | 24 ++-- .../src/pages/telegram/start-quest/index.tsx | 47 +------ 11 files changed, 452 insertions(+), 73 deletions(-) create mode 100644 wondrous-bot-admin/src/assets/botIcon.tsx create mode 100644 wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx create mode 100644 wondrous-bot-admin/src/components/QuestSteps/Steps/Attachment.tsx create mode 100644 wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx create mode 100644 wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx diff --git a/wondrous-bot-admin/index.html b/wondrous-bot-admin/index.html index d2f940a0f8..8e228c185d 100644 --- a/wondrous-bot-admin/index.html +++ b/wondrous-bot-admin/index.html @@ -10,12 +10,13 @@ rel="stylesheet" /> + + Wonderverse Communities
- + - diff --git a/wondrous-bot-admin/src/assets/botIcon.tsx b/wondrous-bot-admin/src/assets/botIcon.tsx new file mode 100644 index 0000000000..4d222de439 --- /dev/null +++ b/wondrous-bot-admin/src/assets/botIcon.tsx @@ -0,0 +1,122 @@ +export const BotIcon = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); diff --git a/wondrous-bot-admin/src/components/PaymentLedger/styles.tsx b/wondrous-bot-admin/src/components/PaymentLedger/styles.tsx index 72210a5183..bf1c3c8326 100644 --- a/wondrous-bot-admin/src/components/PaymentLedger/styles.tsx +++ b/wondrous-bot-admin/src/components/PaymentLedger/styles.tsx @@ -7,11 +7,11 @@ export const StyledCheckbox = styled(Checkbox)` height: 18px; color: #707070; &.Mui-checked { - color: #F8642D; + color: ${({ bgcolor = "#F8642D" }) => bgcolor}; } .MuiSvgIcon-root { - width: 16px; - height: 16px; + width: ${({ width = "16px" }) => width}; + height: ${({ height = "16px" }) => height}; } } `; diff --git a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx new file mode 100644 index 0000000000..ce65293f5e --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx @@ -0,0 +1,35 @@ +import { Grid, Box, Typography, ButtonBase } from "@mui/material"; +import { BotIcon } from "assets/botIcon"; +import { SharedSecondaryButton } from "components/Shared/styles"; +import { StyledViewQuestResults } from "components/ViewQuestResults/styles"; + +export const StepModal = ({ children, step, nextStep, prevStep, disabled, nextStepId, handleSubmit }) => { + return ( + + + Quest Step {step.order} + + + + + {step.prompt} + + + + + {children} + + + {nextStepId ? "Next" : "Submit"} + + {step?.required ? null : ( + + + Skip Step + + + )} + + + ); +}; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/Attachment.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/Attachment.tsx new file mode 100644 index 0000000000..81df66cf75 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/Attachment.tsx @@ -0,0 +1,112 @@ +import Grid from "@mui/material/Grid"; +import EmptyState from "components/EmptyState"; +import FileUpload from "components/Shared/FileUpload"; +import { Label } from "components/QuestsList/styles"; +import ImageList from "@mui/material/ImageList/ImageList"; +import ImageListItem from "@mui/material/ImageListItem"; +import DeleteIcon from "components/Icons/Delete"; + +import AttachmentIcon from "components/Icons/Attachment"; +import { ButtonIconWrapper, SharedSecondaryButton } from "components/Shared/styles"; +import SafeImage from "components/SafeImage"; +import { Box, ButtonBase } from "@mui/material"; +import SubmissionMedia from "components/Shared/SubmissionMedia"; +import { isVideo } from "utils/media"; +import VideoPlayer from "components/Shared/SubmissionMedia/VideoPlayer"; +import { Filename } from "components/Shared/SubmissionMedia/styles"; + +const Media = ({ file }) => { + if (file.type?.includes("image")) { + return ; + } + if (file.type?.includes("video")) { + return ; + } + return {file}; +}; + +export const AttachmentType = ({ step, onChange, value }) => { + const handleAttachMedia = (e) => { + const file = e.target.files[0]; + const media = value || []; + const newMedia = [...media, file]; + onChange(newMedia); + }; + + const getAttachmentTitle = (file) => { + if (file?.name?.length > 16) { + return `${file.name.slice(0, 16)}...`; + } + return file.name; + }; + + const removeAttachment = (attachmentIdx) => { + const mediaUploads = step?.mediaUploads || []; + const newMedia = mediaUploads?.filter((el, idx) => idx !== attachmentIdx); + onChange(newMedia); + }; + + return ( + <> + handleAttachMedia(e)} + accept={"image/*,video/*,application/pdf"} + renderUploadComponent={({ handleAddMedia }) => { + return ( + + + + + + + + + ); + }} + /> + {value?.length ? ( + + {value?.map((attachment, attachmentIdx) => + attachment ? ( + + + + + removeAttachment(attachmentIdx)}> + + + + + + ) : null + )} + + ) : null} + + ); +}; + +export default AttachmentType; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx new file mode 100644 index 0000000000..aff28e4ab0 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx @@ -0,0 +1,97 @@ +import { Box, Grid, Typography } from "@mui/material"; +import { StyledCheckbox } from "components/PaymentLedger/styles"; +import { ErrorText } from "components/Shared/styles"; +import { useMemo } from "react"; +import { TYPES } from "utils/constants"; + +export const OptionSelect = ({ step, onChange, value, setIsActionDisabled, isActionDisabled }) => { + const opacity = useMemo(() => { + if (step.type === TYPES.SINGLE_QUIZ && value && value.length > 0) { + return 0.3; + } + return 1; + }, [value, step.type]); + + const correctValues = step?.options?.filter((option) => option.correct).map((option) => option.text); + + const allCorrect = useMemo(() => { + if (correctValues && correctValues.length > 0) { + if (step?.type === TYPES.SINGLE_QUIZ) { + return correctValues.includes(value?.[0]); + } else { + return ( + correctValues.every((correctValue) => value?.includes(correctValue)) && value?.length === correctValues.length + ); + } + } else { + return null; + } + }, [correctValues, value, step.type]); + + const isCorrect = useMemo(() => { + if (correctValues && correctValues.length > 0) { + if (!allCorrect && !isActionDisabled) { + setIsActionDisabled(true); + } + if (allCorrect && isActionDisabled) { + setIsActionDisabled(false); + } + return allCorrect; + } else return null; + }, [correctValues, value, allCorrect]); + + const handleCheckboxChange = (e, text) => { + if (step.type === TYPES.SINGLE_QUIZ && value?.includes(text)) { + return onChange([]); + } + + if (step.type === TYPES.SINGLE_QUIZ) { + return onChange(e.target.checked ? [text] : []); + } + + let defaultValues = value || []; + const values = e.target.checked ? [...defaultValues, text] : defaultValues?.filter((i) => i !== text); + return onChange(values); + }; + + const sortedOptions = useMemo(() => step?.options?.sort((a, b) => a.position - b.position), [step?.options]); + return ( + + {sortedOptions.map((option, idx) => { + return ( + + 0 && !value.includes(option.text)} + onChange={(e) => handleCheckboxChange(e, option.text)} + /> + + {option.text} + + + ); + })} + {isCorrect !== null && + value?.length && + (isCorrect ? null : Please select only the correct options)} + + ); +}; + +export default OptionSelect; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx index bdb9e9b631..8864ef7bba 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx @@ -2,13 +2,11 @@ import { Grid } from "@mui/material"; import { Label } from "components/AddFormEntity/components/styles"; import TextField from "components/Shared/TextField"; -export const StepTextField = ({ step, onChange, value }) => { +export const StepTextField = ({ step, onChange, value, placeholder = "", type = "text" }) => { return ( <> - - - + ); diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx new file mode 100644 index 0000000000..5748a56023 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx @@ -0,0 +1,4 @@ +export const VerifyButton = () => { + return null; +}; + diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index a63e9ae429..5d763b1743 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -1,34 +1,64 @@ import { TYPES } from "utils/constants"; import { StepTextField } from "./Steps"; -import { Grid } from "@mui/material"; +import { Grid, Typography } from "@mui/material"; import PanelComponent from "components/CreateTemplate/PanelComponent"; -import { CampaignOverviewTitle } from "components/CreateTemplate/styles"; import { useState } from "react"; +import { StepModal } from "./StepModal"; +import OptionSelect from "./Steps/OptionSelect"; +import AttachmentType from "./Steps/Attachment"; +import { VerifyButton } from "./Steps/VerifyButton"; const COMPONENTS_CONFIG: any = { [TYPES.TEXT_FIELD]: StepTextField, + [TYPES.MULTI_QUIZ]: OptionSelect, + [TYPES.SINGLE_QUIZ]: OptionSelect, + [TYPES.NUMBER]: (props) => , + [TYPES.ATTACHMENTS]: AttachmentType, + [TYPES.LINK_CLICK]: VerifyButton, + [TYPES.LIKE_YT_VIDEO]: VerifyButton, + [TYPES.SUBSCRIBE_YT_CHANNEL]: VerifyButton, }; -const QuestStep = ({ step, onChange, value }) => { +const QuestStep = ({ step, onChange, value, isActive, nextStepId, nextStep, prevStep, handleSubmit }) => { const Component: React.FC = COMPONENTS_CONFIG[step?.type]; + const [isActionDisabled, setIsActionDisabled] = useState(false); + if (!isActive) return null; if (Component) { return ( ( - Step {step.order} + + Quest Portal + )} - renderBody={() => onChange({ id: step.id, value })} />} + renderBody={() => ( + + onChange({ id: step.id, value })} + placeholder="Enter answer" + /> + + )} /> ); } @@ -37,22 +67,33 @@ const QuestStep = ({ step, onChange, value }) => { const QuestStepsList = ({ quest }) => { const { steps } = quest || []; + const [activeStepId, setActiveStepId] = useState(steps[0]?.id); const [responses, setResponses] = useState({}); - console.log(responses, "STEPS"); - const handleChange = ({ id, value, skip = false }) => setResponses({ ...responses, [id]: skip ? null : value, }); + const handleSubmit = () => {}; + return ( {steps?.map((step, idx) => { - return ; + return ( + setActiveStepId(steps[idx + 1]?.id)} + prevStep={() => setActiveStepId(steps[idx - 1]?.id)} + onChange={handleChange} + handleSubmit={handleSubmit} + /> + ); })} ); diff --git a/wondrous-bot-admin/src/components/Shared/FileUpload.tsx b/wondrous-bot-admin/src/components/Shared/FileUpload.tsx index 3f02b074a6..471c5d0917 100644 --- a/wondrous-bot-admin/src/components/Shared/FileUpload.tsx +++ b/wondrous-bot-admin/src/components/Shared/FileUpload.tsx @@ -1,8 +1,8 @@ -import AttachmentIcon from 'components/Icons/Attachment'; -import { useRef } from 'react'; -import { ButtonIconWrapper } from './styles'; +import AttachmentIcon from "components/Icons/Attachment"; +import { useRef } from "react"; +import { ButtonIconWrapper } from "./styles"; -const FileUpload = ({ onChange }) => { +const FileUpload = ({ onChange, renderUploadComponent = null, accept = "image/*" }) => { const inputRef = useRef(null); const handleAddMedia = () => inputRef.current.click(); @@ -10,17 +10,21 @@ const FileUpload = ({ onChange }) => { return ( <> { inputRef.current = input; }} onChange={onChange} - style={{ display: 'none' }} - accept='image/*' + style={{ display: "none" }} + accept={accept} /> - handleAddMedia()}> - - + {renderUploadComponent ? ( + renderUploadComponent({ handleAddMedia }) + ) : ( + handleAddMedia()}> + + + )} ); }; diff --git a/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx b/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx index c87e616aa5..1dce97cfd0 100644 --- a/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx +++ b/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx @@ -56,9 +56,9 @@ export interface IWebApp { } export const TelegramStartQuest = () => { - const [webApp, setWebApp] = useState(null); let { id, ...rest } = useParams(); + const webApp = (window as any)?.Telegram?.WebApp; const [getQuestById, { data, loading, refetch }] = useLazyQuery(GET_QUEST_BY_ID, { fetchPolicy: "network-only", onCompleted: (data) => { @@ -70,21 +70,6 @@ export const TelegramStartQuest = () => { fetchPolicy: "network-only", }); - useLayoutEffect(() => { - const script = document.createElement("script"); - script.src = "https://telegram.org/js/telegram-web-app.js"; - script.async = true; - document.body.appendChild(script); - const app = (window as any).Telegram?.WebApp; - if (app) { - app.ready(); - setWebApp(app); - } - return () => { - document.body.removeChild(script); - }; - }, []); - const value = { webApp, unsafeData: webApp?.initDataUnsafe, @@ -107,20 +92,21 @@ export const TelegramStartQuest = () => { }); } }; + useEffect(() => { - handleStart(); if (!webApp?.initDataUnsafe?.user?.id) { return; } + handleStart(); }, [webApp?.initDataUnsafe?.user?.id, webApp?.initDataUnsafe?.user?.username]); const { user, unsafeData } = value; - console.log(data, loading) + return ( { }} bgType={BG_TYPES.QUESTS} > - {data?.getQuestById ? : } + {data?.getQuestById ? : } - //
- // {canStartData ? JSON.stringify(data?.getQuestById) : "NO DATA CAN START"} - // QUEST_ID = {id} - // {user ? ( - //
- //

Welcome {user?.username}

- // User data: - //
{JSON.stringify(user, null, 2)}
- // Enter Web App data: - //
{JSON.stringify(webApp, null, 2)}
- // UNSAFE DATA - //
{JSON.stringify(unsafeData)}
- //
- // ) : ( - //
Make sure web app is opened from telegram client
- // )} - //
); }; From 39a8b4dddb88d28d898e14081523d041616762df Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Mon, 28 Aug 2023 21:40:26 +0300 Subject: [PATCH 11/31] more quest steps --- .../src/components/AddFormEntity/index.tsx | 30 +- .../components/QuestSteps/StepModal/index.tsx | 9 +- .../QuestSteps/Steps/VerifyButton.tsx | 437 +++++++++++++++++- .../src/components/QuestSteps/SubmitQuest.tsx | 48 ++ .../src/components/QuestSteps/index.tsx | 241 ++++++++-- .../src/components/QuestSteps/styles.tsx | 6 + .../src/components/Shared/Spinner/index.tsx | 21 + .../src/graphql/fragments/user.ts | 2 + .../src/graphql/mutations/quest.ts | 10 + .../src/graphql/queries/quest.ts | 60 +++ .../src/pages/oauth/google/callback.tsx | 38 +- .../src/pages/telegram/start-quest/index.tsx | 101 +--- wondrous-bot-admin/src/utils/common.tsx | 44 +- wondrous-bot-admin/src/utils/constants.tsx | 42 ++ .../src/utils/context/TakeQuestContext.tsx | 5 + wondrous-bot-admin/src/utils/hooks.tsx | 3 + 16 files changed, 917 insertions(+), 180 deletions(-) create mode 100644 wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx create mode 100644 wondrous-bot-admin/src/components/QuestSteps/styles.tsx create mode 100644 wondrous-bot-admin/src/components/Shared/Spinner/index.tsx create mode 100644 wondrous-bot-admin/src/utils/context/TakeQuestContext.tsx diff --git a/wondrous-bot-admin/src/components/AddFormEntity/index.tsx b/wondrous-bot-admin/src/components/AddFormEntity/index.tsx index 8ed82997e3..31e715db57 100644 --- a/wondrous-bot-admin/src/components/AddFormEntity/index.tsx +++ b/wondrous-bot-admin/src/components/AddFormEntity/index.tsx @@ -125,21 +125,21 @@ const AddFormEntity = ({ steps, setSteps, stepCache, handleRemove, refs, setRem const handleChangeType = (type, order, idx) => { if (!type) return; - if ( - (plan === PricingOptionsTitle.Basic || plan === PricingOptionsTitle.Hobby) && - (type === TYPES.SUBSCRIBE_YT_CHANNEL || type === TYPES.LIKE_YT_VIDEO || type === TYPES.CUSTOM_ONCHAIN_ACTION) - ) { - setPaywall(true); - setPaywallMessage("This feature is only available on the Pro plan and above"); - return; - } - if ( - (plan === PricingOptionsTitle.Premium || plan === PricingOptionsTitle.Ecosystem) && - type === TYPES.CUSTOM_ONCHAIN_ACTION - ) { - setOpenEcosystemDialog(true); - return; - } + // if ( + // (plan === PricingOptionsTitle.Basic || plan === PricingOptionsTitle.Hobby) && + // (type === TYPES.SUBSCRIBE_YT_CHANNEL || type === TYPES.LIKE_YT_VIDEO || type === TYPES.CUSTOM_ONCHAIN_ACTION) + // ) { + // setPaywall(true); + // setPaywallMessage("This feature is only available on the Pro plan and above"); + // return; + // } + // if ( + // (plan === PricingOptionsTitle.Premium || plan === PricingOptionsTitle.Ecosystem) && + // type === TYPES.CUSTOM_ONCHAIN_ACTION + // ) { + // setOpenEcosystemDialog(true); + // return; + // } setErrors((prev) => { return { ...prev, diff --git a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx index ce65293f5e..45df96addd 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx @@ -2,8 +2,11 @@ import { Grid, Box, Typography, ButtonBase } from "@mui/material"; import { BotIcon } from "assets/botIcon"; import { SharedSecondaryButton } from "components/Shared/styles"; import { StyledViewQuestResults } from "components/ViewQuestResults/styles"; +import { useTakeQuest } from "utils/hooks"; + +export const StepModal = ({ children, step, disabled, nextStepId }) => { + const { nextStep, handleSubmit } = useTakeQuest(); -export const StepModal = ({ children, step, nextStep, prevStep, disabled, nextStepId, handleSubmit }) => { return ( @@ -19,8 +22,8 @@ export const StepModal = ({ children, step, nextStep, prevStep, disabled, nextSt {children} - - {nextStepId ? "Next" : "Submit"} + + Next {step?.required ? null : ( diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx index 5748a56023..50bf4ac166 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx @@ -1,4 +1,439 @@ -export const VerifyButton = () => { +import { useLazyQuery, useMutation } from "@apollo/client"; +import { CircularProgress, Grid, Typography } from "@mui/material"; +import { Label } from "components/AddFormEntity/components/styles"; +import Spinner from "components/Shared/Spinner"; +import { ErrorText, SharedSecondaryButton } from "components/Shared/styles"; +import { + GET_CMTY_USER_INFO, + GET_INTEGRATION_CMTY_USER, + VERIFY_LINK_CLICKED, + VERIFY_SNAPSHOT_PROPOSAL_VOTE, + VERIFY_SNAPSHOT_SPACE_VOTE, + VERIFY_YT_LIKED, + VERIFY_YT_SUBSCRIPTION, +} from "graphql/queries"; +import { getGoogleOauthUrl } from "pages/oauth/google/callback"; +import { useEffect, useMemo, useState } from "react"; +import { getYouTubeVideoId } from "services/validators/customValidation"; +import { getBaseUrl, getWeb3ConnectUrl, getYoutubeChannelId } from "utils/common"; +import { TYPES } from "utils/constants"; +import { useTakeQuest } from "utils/hooks"; + +const LinkComponent = ({ + loading, + link, + onClick, + label = "Click on the link below to verify", + linkText = "Visit Link", + error = null, +}) => { + return ( + <> + {loading ? : null} + + + + {linkText} + + + {error ? {error} : null} + + ); +}; + +const GoogleVerify = ({ telegramUserId, callback }) => { + const handleClick = () => { + return callback?.(); + }; + const link = getGoogleOauthUrl({ telegramUserId }); + + return ( + + Connect Google + + ); +}; + +const Web3Connect = ({ telegramUserId, callback }) => { + const handleClick = () => { + return callback?.(); + }; + const link = getWeb3ConnectUrl({ telegramUserId }); + return ( + + Connect Wallet + + ); +}; + +const LinkClickButton = ({ step, cmtyUser, handleLinkClick, startCmtyUserPolling }) => { + const { nextStep, onChange } = useTakeQuest(); + const [verifyLinkClick, { startPolling, stopPolling, loading }] = useLazyQuery(VERIFY_LINK_CLICKED, { + onCompleted: (data) => { + if (data?.verifyLinkClicked?.success) { + stopPolling(); + onChange({ + id: step?.id, + value: true, + }); + nextStep(); + } + }, + }); + + const link = useMemo(() => { + const baseUrl = getBaseUrl(); + const url = step?.additionalData?.linkClickUrl; + const linkQuery = JSON.stringify({ + url, + cmtyUserId: cmtyUser?.id, + questStepId: step?.id, + }); + const query = btoa(linkQuery); + return `${baseUrl}/verify-link?query=${query}`; + }, [step]); + + const onClick = async () => { + return handleLinkClick({ + action: async () => { + await verifyLinkClick({ + variables: { + cmtyUserId: cmtyUser?.id, + url: step?.additionalData?.linkClickUrl, + questStepId: step?.id, + }, + }); + startPolling(1000); + }, + callback: stopPolling(), + timeout: 30000, + }); + }; + return ; +}; + +const YoutubeButton = ({ step, cmtyUser, startCmtyUserPolling, stopCmtyUserPolling }) => { + const { nextStep, onChange } = useTakeQuest(); + const [verifyYoutubeSubscription, { loading: ytSubscriptionLoading, error, data: ytData }] = + useLazyQuery(VERIFY_YT_SUBSCRIPTION); + + const [verifyYoutubeLike, { loading: ytLikeLoading, error: ytLikeError }] = useLazyQuery(VERIFY_YT_LIKED); + + const [getCmtyUserInfo, { data, startPolling: startCmtyUserInfoPolling, stopPolling: stopCmtyUserInfoPolling }] = + useLazyQuery(GET_CMTY_USER_INFO, { + notifyOnNetworkStatusChange: true, + }); + + useEffect(() => { + if (data?.getCmtyUserInfo?.googleInfo) { + stopCmtyUserInfoPolling(); + } + }, [data?.getCmtyUserInfo?.googleInfo, stopCmtyUserInfoPolling]); + + const ytChannelLink = step?.additionalData?.ytChannelLink; + const ytInfo = useMemo(() => { + let data = { + channelId: null, + channelHandle: null, + videoId: null, + }; + + switch (step?.type) { + case TYPES.LIKE_YT_VIDEO: + data.videoId = getYouTubeVideoId(step?.additionalData?.ytVideoLink); + break; + case TYPES.SUBSCRIBE_YT_CHANNEL: + const channelData = getYoutubeChannelId(ytChannelLink); + data.channelId = channelData?.channelId; + data.channelHandle = channelData?.channelHandle; + break; + default: + break; + } + + return data; + }, [ytChannelLink, step?.additionalData?.ytVideoLink, step?.type]); + + const handleVerifySubscription = async () => { + const { data, error } = await verifyYoutubeSubscription({ + variables: { + cmtyUserId: cmtyUser?.id, + channelId: ytInfo?.channelId, + channelHandle: ytInfo?.channelHandle, + }, + }); + if (data?.verifyYoutubeSubscription?.subscribed) { + onChange({ + id: step?.id, + value: true, + }); + return nextStep(); + } + }; + + const handleVerifyLike = async () => { + const { data, error } = await verifyYoutubeLike({ + variables: { + cmtyUserId: cmtyUser?.id, + videoId: ytInfo?.videoId, + }, + }); + if (data?.verifyYoutubeVideoLike?.liked) { + onChange({ + id: step?.id, + value: true, + }); + return nextStep(); + } + }; + + useEffect(() => { + getCmtyUserInfo({ + variables: { + cmtyUserId: cmtyUser?.id, + }, + }); + }, []); + + if (!data?.getCmtyUserInfo?.cmtyUserId) { + return ; + } + + const googleVerifyCallback = () => { + setTimeout(() => startCmtyUserInfoPolling(1000), 3000); + }; + + const errorObject = error || ytLikeError; + + if ( + !data?.getCmtyUserInfo?.googleInfo || + errorObject?.graphQLErrors?.[0]?.extensions?.errorCode === "google_not_authorized" + ) { + return ; + } + + const onClick = () => { + if (step.type === TYPES.LIKE_YT_VIDEO) { + return handleVerifyLike(); + } + return handleVerifySubscription(); + }; + + const label = step.type === TYPES.LIKE_YT_VIDEO ? "Verify YouTube Like" : "Verify YouTube Subscription"; + return ( + + ); +}; + +const SnapshotButton = ({ step, cmtyUser, handleLinkClick, startCmtyUserPolling, stopCmtyUserPolling }) => { + const snapshotProposalLink = step?.additionalData?.snapshotProposalLink; + const snapshotSpaceLink = step?.additionalData?.snapshotSpaceLink; + const snapshotVoteTimes = step?.additionalData?.snapshotVoteTimes; + + const isProposalType = step.type === TYPES.SNAPSHOT_PROPOSAL_VOTE; + + const { onChange, nextStep } = useTakeQuest(); + + const [ + verifySnapshotProposalVote, + { loading, error, data, startPolling: startProposalPolling, stopPolling: stopProposalPolling }, + ] = useLazyQuery(VERIFY_SNAPSHOT_PROPOSAL_VOTE, { + fetchPolicy: "network-only", + nextFetchPolicy: "network-only", + notifyOnNetworkStatusChange: true, + onCompleted: (data) => { + if (data?.verifySnapshotProposalVote?.userVotedProposal) { + stopSpacePolling(); + onChange({ + id: step?.id, + value: true, + }); + return nextStep(); + } + }, + }); + + const [ + verifySnapshotSpaceVote, + { + loading: spaceLoading, + error: spaceVoteError, + data: spaceData, + startPolling: startSpacePolling, + stopPolling: stopSpacePolling, + }, + ] = useLazyQuery(VERIFY_SNAPSHOT_SPACE_VOTE, { + fetchPolicy: "network-only", + nextFetchPolicy: "network-only", + notifyOnNetworkStatusChange: true, + onCompleted: (data) => { + if (data?.verifySnapshotSpaceVote?.userVotedSpace) { + stopSpacePolling(); + onChange({ + id: step?.id, + value: true, + }); + return nextStep(); + } + }, + }); + + const label = isProposalType + ? `Please vote on this proposal` + : `Please vote in this space at least ${snapshotVoteTimes} times`; + + const errorObj = error || spaceVoteError; + + const web3VerifyCallback = () => { + setTimeout(() => startCmtyUserPolling(1000), 3000); + }; + + const handleVerifyProposalVote = async () => { + const proposalId = snapshotProposalLink?.split("/")[6]; + + // TODO: on the API, switch to use only cmtyUser ID instead of telegram / discord ids + const { data } = await verifySnapshotProposalVote({ + variables: { + telegramUserId: cmtyUser.telegramId, + proposalId, + }, + }); + if (data?.verifySnapshotProposalVote?.userVotedProposal === false) { + startProposalPolling(1000); + setTimeout(() => stopProposalPolling(), 30000); + } + }; + + const handleVerifySpaceVotes = async () => { + const { data } = await verifySnapshotSpaceVote({ + variables: { + telegramUserId: cmtyUser.telegramId, + stepId: step.id, + voteTimes: step?.additionalData?.snapshotVoteTimes, + }, + }); + if (data?.verifySnapshotSpaceVote?.userVotedSpace === false) { + startProposalPolling(1000); + setTimeout(() => stopProposalPolling(), 30000); + } + }; + + const onClick = () => { + if (isProposalType) { + return handleVerifyProposalVote(); + } + return handleVerifySpaceVotes(); + }; + + const errorMessage = useMemo(() => { + if (spaceData?.verifySnapshotSpaceVote?.userVotedSpace === false) { + return "You did not vote in the space the correct number of times, please try again"; + } + if (data?.verifySnapshotProposalVote?.userVotedProposal === false) { + return "Proposal was not voted on, try again"; + } + if (errorObj) { + return "Something went wrong. Please try again or contact support"; + } return null; + }, [spaceData, data, errorObj]); + + if (!cmtyUser?.web3Address) { + return ; + } + + return ( + + ); +}; + +const COMPONENTS = { + [TYPES.LINK_CLICK]: LinkClickButton, + [TYPES.SUBSCRIBE_YT_CHANNEL]: YoutubeButton, + [TYPES.LIKE_YT_VIDEO]: YoutubeButton, + [TYPES.SNAPSHOT_PROPOSAL_VOTE]: SnapshotButton, + [TYPES.SNAPSHOT_SPACE_VOTE]: SnapshotButton, }; +export const VerifyButton = ({ step }) => { + const [getIntegrationCmtyUser, { data, refetch, loading, startPolling, stopPolling }] = useLazyQuery( + GET_INTEGRATION_CMTY_USER, + { + notifyOnNetworkStatusChange: true, + } + ); + + const handleLinkClick = async ({ action, callback, timeout = 3000 }) => { + if (action) { + await action(); + } + + setTimeout(() => { + callback(); + }, timeout); + }; + + const { telegramUser } = useTakeQuest(); + + const handleFetch = async () => { + const { data } = await getIntegrationCmtyUser({ + variables: { + telegramUserId: telegramUser?.id?.toString(), + }, + }); + }; + + useEffect(() => { + handleFetch(); + }, []); + + if (!data?.getIntegrationCmtyUser?.id) { + return ( + + + + ); + } + + const Component = COMPONENTS[step.type]; + + return ( + + {Component ? ( + + ) : null} + + ); +}; diff --git a/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx b/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx new file mode 100644 index 0000000000..a458cce9b7 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx @@ -0,0 +1,48 @@ +import { Box, Grid, Typography } from "@mui/material"; +import PanelComponent from "components/CreateTemplate/PanelComponent"; +import { DEFAULT_BANNER_IMAGES } from "utils/constants"; +import { Image } from "./styles"; +import { SharedSecondaryButton } from "components/Shared/styles"; + +const SubmitQuest = ({ + handleSubmit +}) => { + return ( + ( + + + Quest Portal + + + )} + renderBody={() => ( + + + Ready to submit the quest? + + + Do you want to submit your response? + + + + + Edit Responses + Submit Quest + + + )} + /> + ); +}; + +export default SubmitQuest; diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index 5d763b1743..e1f5e5ac74 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -1,12 +1,36 @@ -import { TYPES } from "utils/constants"; +import { SELECT_STEP_TYPES, TYPES } from "utils/constants"; import { StepTextField } from "./Steps"; import { Grid, Typography } from "@mui/material"; import PanelComponent from "components/CreateTemplate/PanelComponent"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { StepModal } from "./StepModal"; import OptionSelect from "./Steps/OptionSelect"; import AttachmentType from "./Steps/Attachment"; import { VerifyButton } from "./Steps/VerifyButton"; +import { GET_QUEST_BY_ID, USER_CAN_START_QUEST } from "graphql/queries"; +import { useLazyQuery, useMutation } from "@apollo/client"; +import { useParams } from "react-router-dom"; +import { transformAndUploadMedia } from "utils/media"; +import TakeQuestContext from "utils/context/TakeQuestContext"; +import { useTakeQuest } from "utils/hooks"; +import SubmitQuest from "./SubmitQuest"; +import { SUBMIT_QUEST } from "graphql/mutations"; + +const handleMediaUpload = async (mediaUploads) => + Promise.all( + mediaUploads.map(async (file) => { + try { + const { filename, fileType } = await transformAndUploadMedia({ file }); + return { + uploadSlug: filename, + type: fileType, + name: file.name, + }; + } catch (error) { + return null; + } + }) + ); const COMPONENTS_CONFIG: any = { [TYPES.TEXT_FIELD]: StepTextField, @@ -15,13 +39,19 @@ const COMPONENTS_CONFIG: any = { [TYPES.NUMBER]: (props) => , [TYPES.ATTACHMENTS]: AttachmentType, [TYPES.LINK_CLICK]: VerifyButton, - [TYPES.LIKE_YT_VIDEO]: VerifyButton, [TYPES.SUBSCRIBE_YT_CHANNEL]: VerifyButton, + [TYPES.LIKE_YT_VIDEO]: VerifyButton, + + [TYPES.SNAPSHOT_PROPOSAL_VOTE]: VerifyButton, + [TYPES.SNAPSHOT_SPACE_VOTE]: VerifyButton, + [TYPES.VERIFY_TOKEN_HOLDING]: VerifyButton, + [TYPES.DATA_COLLECTION]: () => null, }; -const QuestStep = ({ step, onChange, value, isActive, nextStepId, nextStep, prevStep, handleSubmit }) => { +const QuestStep = ({ step, value, isActive, nextStepId, isWebView = false }) => { const Component: React.FC = COMPONENTS_CONFIG[step?.type]; const [isActionDisabled, setIsActionDisabled] = useState(false); + const { onChange } = useTakeQuest(); if (!isActive) return null; if (Component) { return ( @@ -41,14 +71,7 @@ const QuestStep = ({ step, onChange, value, isActive, nextStepId, nextStep, prev )} renderBody={() => ( - + { - const { steps } = quest || []; - const [activeStepId, setActiveStepId] = useState(steps[0]?.id); +const QuestStepsList = () => { + let { id } = useParams(); + + const [submitQuest] = useMutation(SUBMIT_QUEST); + + const [activeStepId, setActiveStepId] = useState(null); const [responses, setResponses] = useState({}); + const [showSubmitView, setShowSubmitView] = useState(false); + + const [isEditMode, setIsEditMode] = useState(false); + + const webApp = (window as any)?.Telegram?.WebApp; + const [getQuestById, { data, loading, refetch }] = useLazyQuery(GET_QUEST_BY_ID, { + fetchPolicy: "network-only", + onCompleted: (data) => { + document.title = data?.getQuestById?.title; + }, + }); + + const [canUserStartQuest, { data: canStartData, error: canStartError }] = useLazyQuery(USER_CAN_START_QUEST, { + fetchPolicy: "network-only", + }); - const handleChange = ({ id, value, skip = false }) => + useEffect(() => { + if (!webApp?.initDataUnsafe?.user?.id) { + return; + } + handleStart(); + }, [webApp?.initDataUnsafe?.user?.id, webApp?.initDataUnsafe?.user?.username]); + + const handleStart = async () => { + const { data } = await canUserStartQuest({ + variables: { + questId: id, + telegramUserId: webApp?.initDataUnsafe?.user?.id?.toString(), + telegramUsername: webApp?.initDataUnsafe?.user?.username, + }, + }); + if (data?.userCanStartQuest?.canStart) { + const { data: questData } = await getQuestById({ + variables: { + questId: id, + }, + }); + if (questData?.getQuestById?.id) { + setActiveStepId(questData.getQuestById?.steps?.[0]?.id); + } + } + }; + + const onChange = ({ id, value, skip = false }) => setResponses({ ...responses, [id]: skip ? null : value, }); - const handleSubmit = () => {}; + const handleSubmit = async () => { + const questSubmissions = []; + + console.log(responses, "RESPONSES"); + for (const step of data?.getQuestById.steps) { + const answer = responses[step.id]; + const isQuestSkipped = responses[step.id] === null; + if (step.type === TYPES.TEXT_FIELD) { + questSubmissions.push({ + stepId: step.id, + content: isQuestSkipped ? null : answer, + skipped: isQuestSkipped, + order: step.order, + }); + } else if (step.type === TYPES.NUMBER) { + questSubmissions.push({ + stepId: step.id, + content: answer, + order: step.order, + }); + } else if (SELECT_STEP_TYPES.includes(step.type)) { + questSubmissions.push({ + stepId: step.id, + order: step.order, + skipped: isQuestSkipped, + selectedValues: isQuestSkipped ? null : answer, + }); + } else if (step.type === TYPES.ATTACHMENTS) { + //TODO: fix upload media from web app , probably separate endpoint + // const stepsMedia = isQuestSkipped ? [null] : await handleMediaUpload(answer); + // console.log(stepsMedia, 'STEPS MEDIA') + // questSubmissions.push({ + // stepId: step.id, + // order: step.order, + // skipped: isQuestSkipped, + // attachments: isQuestSkipped ? null : stepsMedia.map((media) => ({ + // filename: media.name, + // type: media.type, + // uploadSlug: media.uploadSlug + // })) + // }) + } else if ([TYPES.LIKE_YT_VIDEO, TYPES.SUBSCRIBE_YT_CHANNEL].includes(step.type)) { + questSubmissions.push({ + stepId: step.id, + order: step.order, + skipped: isQuestSkipped, + verified: isQuestSkipped ? false : true, + }); + } else if ([TYPES.SNAPSHOT_PROPOSAL_VOTE, TYPES.SNAPSHOT_SPACE_VOTE].includes(step.type)) { + questSubmissions.push({ + stepId: step.id, + order: step.order, + skipped: isQuestSkipped, + verified: isQuestSkipped ? false : true, + }); + } + } + const submissionInput = { + questId: data?.getQuestById?.id, + telegramUserId: webApp?.initDataUnsafe?.user?.id?.toString(), + telegramUsername: webApp?.initDataUnsafe?.user?.username, + stepsData: questSubmissions, + }; + + const { data: submitQuestResultData } = await submitQuest({ + variables: submissionInput, + }); + //TODO: handle reward && next screen + // const stepsSubmission = camelToSnakeArr(questSubmissions); + // const submissionInput = { + // quest_id: questId, + // telegram_user_id: ctx.from.id, + // telegram_username: ctx.from.username, + // steps_data: stepsSubmission + // }; + }; + + const steps = data?.getQuestById?.steps || []; + + const nextStep = () => { + const currentStepIdx = steps?.findIndex((step) => step.id === activeStepId); + const nextStepId = steps[currentStepIdx + 1]?.id; + + if (!nextStepId) { + return setShowSubmitView(true); + } + setActiveStepId(steps[currentStepIdx + 1]?.id); + }; + + const prevStep = () => { + const currentStepIdx = steps?.findIndex((step) => step.id === activeStepId); + setActiveStepId(steps[currentStepIdx - 1]?.id); + }; return ( - - {steps?.map((step, idx) => { - return ( - setActiveStepId(steps[idx + 1]?.id)} - prevStep={() => setActiveStepId(steps[idx - 1]?.id)} - onChange={handleChange} - handleSubmit={handleSubmit} - /> - ); - })} - + + + {showSubmitView ? ( + + ) : ( + <> + {data?.getQuestById?.steps?.map((step, idx) => { + return ( + + ); + })} + + )} + + ); }; diff --git a/wondrous-bot-admin/src/components/QuestSteps/styles.tsx b/wondrous-bot-admin/src/components/QuestSteps/styles.tsx new file mode 100644 index 0000000000..c20b121af3 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/styles.tsx @@ -0,0 +1,6 @@ +import styled from "styled-components"; + +export const Image = styled.img` + height: 81px; + width: auto; +`; diff --git a/wondrous-bot-admin/src/components/Shared/Spinner/index.tsx b/wondrous-bot-admin/src/components/Shared/Spinner/index.tsx new file mode 100644 index 0000000000..2e59128d61 --- /dev/null +++ b/wondrous-bot-admin/src/components/Shared/Spinner/index.tsx @@ -0,0 +1,21 @@ +import { CircularProgress } from "@mui/material"; + +interface IProps { + size?: string | number; + thickness?: number; + sx?: any; +} + +export default function Spinner({ size = 30, thickness = 5, sx = {} }: IProps) { + return ( + + ); +} diff --git a/wondrous-bot-admin/src/graphql/fragments/user.ts b/wondrous-bot-admin/src/graphql/fragments/user.ts index bc80833277..b3ca7cb2e0 100644 --- a/wondrous-bot-admin/src/graphql/fragments/user.ts +++ b/wondrous-bot-admin/src/graphql/fragments/user.ts @@ -88,5 +88,7 @@ export const CmtyUserFragment = gql` twitterInfo { twitterUsername } + telegramId + telegramUsername } ` diff --git a/wondrous-bot-admin/src/graphql/mutations/quest.ts b/wondrous-bot-admin/src/graphql/mutations/quest.ts index 6afb8c626d..bc0260e681 100644 --- a/wondrous-bot-admin/src/graphql/mutations/quest.ts +++ b/wondrous-bot-admin/src/graphql/mutations/quest.ts @@ -130,4 +130,14 @@ export const REMOVE_QUEST_STEP_MEDIA = gql` success } } +`; + + + +export const SUBMIT_QUEST = gql` + mutation createQuestSubmission($questId: String, $telegramUserId: String, $telegramUsername: String, $stepsData: [StepSubmissionInput]) { + createQuestSubmission(questId: $questId, telegramUserId: $telegramUserId, telegramUsername: $telegramUsername, stepsData: $stepsData) { + success + } + } `; \ No newline at end of file diff --git a/wondrous-bot-admin/src/graphql/queries/quest.ts b/wondrous-bot-admin/src/graphql/queries/quest.ts index 248952614f..4a2e490607 100644 --- a/wondrous-bot-admin/src/graphql/queries/quest.ts +++ b/wondrous-bot-admin/src/graphql/queries/quest.ts @@ -201,3 +201,63 @@ export const USER_CAN_START_QUEST = gql` } } `; + +export const GET_INTEGRATION_CMTY_USER = gql` + query getIntegrationCmtyUser($telegramUserId: String) { + getIntegrationCmtyUser(telegramUserId: $telegramUserId) { + ...CmtyUserFragment + } + } + + ${CmtyUserFragment} +`; + +export const GET_CMTY_USER_INFO = gql` + query getCmtyUserInfo($cmtyUserId: String) { + getCmtyUserInfo(cmtyUserId: $cmtyUserId) { + cmtyUserId + googleInfo { + expireAt + } + } + } +`; +export const VERIFY_LINK_CLICKED = gql` + query verifyLinkClicked($cmtyUserId: String, $questStepId: String, $url: String) { + verifyLinkClicked(cmtyUserId: $cmtyUserId, questStepId: $questStepId, url: $url) { + success + } + } +`; + +export const VERIFY_YT_SUBSCRIPTION = gql` + query verifyYoutubeSubscription($cmtyUserId: String, $channelId: String, $channelHandle: String) { + verifyYoutubeSubscription(cmtyUserId: $cmtyUserId, channelId: $channelId, channelHandle: $channelHandle) { + subscribed + } + } +`; + +export const VERIFY_YT_LIKED = gql` + query verifyYoutubeVideoLike($cmtyUserId: String, $videoId: String) { + verifyYoutubeVideoLike(cmtyUserId: $cmtyUserId, videoId: $videoId) { + liked + } + } +`; + +export const VERIFY_SNAPSHOT_PROPOSAL_VOTE = gql` + query verifySnapshotProposalVote($telegramUserId: String, $proposalId: String) { + verifySnapshotProposalVote(telegramUserId: $telegramUserId, proposalId: $proposalId) { + userVotedProposal + } + } +`; + +export const VERIFY_SNAPSHOT_SPACE_VOTE = gql` + query verifySnapshotSpaceVote($telegramUserId: String, $stepId: String, $voteTimes: Int) { + verifySnapshotSpaceVote(telegramUserId: $telegramUserId, stepId: $stepId, voteTimes: $voteTimes) { + userVotedSpace + } + } +`; \ No newline at end of file diff --git a/wondrous-bot-admin/src/pages/oauth/google/callback.tsx b/wondrous-bot-admin/src/pages/oauth/google/callback.tsx index 54489189a8..05f8b17a04 100644 --- a/wondrous-bot-admin/src/pages/oauth/google/callback.tsx +++ b/wondrous-bot-admin/src/pages/oauth/google/callback.tsx @@ -6,24 +6,30 @@ import { useEffect, useState } from "react"; import { useSearchParams } from "react-router-dom"; import { getBaseUrl } from "utils/common"; -function getGoogleOauthUrl(discordId) { - const GOOGLE_CLIENT_ID = "276263235787-efsi17itjf4d230126shg69h6r6qagf7.apps.googleusercontent.com"; - const baseUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${GOOGLE_CLIENT_ID}&response_type=code`; - const redirectUrl = encodeURIComponent(`${getBaseUrl()}/oauth/google/callback`); - const state = encodeURIComponent( - JSON.stringify({ - discordId, - }) - ); - const accessType = "offline"; - const scope = encodeURIComponent(["email", "profile", "https://www.googleapis.com/auth/youtube"].join(" ")); - console.log(scope); - //'email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl' - const oauthUrl = `${baseUrl}&redirect_uri=${redirectUrl}&state=${state}&scope=${scope}&access_type=${accessType}`; - console.log(oauthUrl); - return oauthUrl; +export function getGoogleOauthUrl({telegramUserId = null, discordId = null}) { + const GOOGLE_CLIENT_ID = '276263235787-efsi17itjf4d230126shg69h6r6qagf7.apps.googleusercontent.com'; + const baseUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${GOOGLE_CLIENT_ID}&response_type=code`; + const redirectUrl = encodeURIComponent(`${getBaseUrl()}/oauth/google/callback`); + + const payload = {}; + + if(telegramUserId) { + payload['telegramUserId'] = telegramUserId + }; + if(discordId) { + payload['discordId'] = discordId + } + const state = encodeURIComponent( + JSON.stringify(payload) + ); + const accessType = 'offline'; + const scope = encodeURIComponent(['email', 'profile', 'https://www.googleapis.com/auth/youtube'].join(' ')); + //'email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl' + const oauthUrl = `${baseUrl}&redirect_uri=${redirectUrl}&state=${state}&scope=${scope}&access_type=${accessType}`; + return oauthUrl; } + const GoogleOauthCallbackPage = () => { // getGoogleOauthUrl("542545105903419404"); const [searchParams] = useSearchParams(); diff --git a/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx b/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx index 1dce97cfd0..cc9788f83b 100644 --- a/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx +++ b/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx @@ -1,107 +1,8 @@ -import { useLazyQuery } from "@apollo/client"; -import PageSpinner from "components/PageSpinner"; import QuestSteps from "components/QuestSteps"; import PageWrapper from "components/Shared/PageWrapper"; -import { GET_QUEST_BY_ID, USER_CAN_START_QUEST } from "graphql/queries"; -import { useEffect, useLayoutEffect, useMemo, useState } from "react"; -import { useLocation, useParams } from "react-router-dom"; import { BG_TYPES } from "utils/constants"; -export interface ITelegramUser { - id: number; - first_name: string; - last_name: string; - username: string; - language_code: string; -} - -export interface IWebApp { - initData: string; - initDataUnsafe: { - query_id: string; - user: ITelegramUser; - auth_date: string; - hash: string; - }; - version: string; - platform: string; - colorScheme: string; - themeParams: { - link_color: string; - button_color: string; - button_text_color: string; - secondary_bg_color: string; - hint_color: string; - bg_color: string; - text_color: string; - }; - isExpanded: boolean; - viewportHeight: number; - viewportStableHeight: number; - isClosingConfirmationEnabled: boolean; - headerColor: string; - backgroundColor: string; - BackButton: { - isVisible: boolean; - }; - MainButton: { - text: string; - color: string; - textColor: string; - isVisible: boolean; - isProgressVisible: boolean; - isActive: boolean; - }; - HapticFeedback: any; -} - export const TelegramStartQuest = () => { - let { id, ...rest } = useParams(); - - const webApp = (window as any)?.Telegram?.WebApp; - const [getQuestById, { data, loading, refetch }] = useLazyQuery(GET_QUEST_BY_ID, { - fetchPolicy: "network-only", - onCompleted: (data) => { - document.title = data?.getQuestById?.title; - }, - }); - - const [canUserStartQuest, { data: canStartData, error: canStartError }] = useLazyQuery(USER_CAN_START_QUEST, { - fetchPolicy: "network-only", - }); - - const value = { - webApp, - unsafeData: webApp?.initDataUnsafe, - user: webApp?.initDataUnsafe.user, - }; - - const handleStart = async () => { - const { data } = await canUserStartQuest({ - variables: { - questId: id, - telegramUserId: webApp?.initDataUnsafe?.user?.id?.toString(), - telegramUsername: webApp?.initDataUnsafe?.user?.username, - }, - }); - if (data?.userCanStartQuest?.canStart) { - getQuestById({ - variables: { - questId: id, - }, - }); - } - }; - - useEffect(() => { - if (!webApp?.initDataUnsafe?.user?.id) { - return; - } - handleStart(); - }, [webApp?.initDataUnsafe?.user?.id, webApp?.initDataUnsafe?.user?.username]); - - const { user, unsafeData } = value; - return ( { }} bgType={BG_TYPES.QUESTS} > - {data?.getQuestById ? : } + ); }; diff --git a/wondrous-bot-admin/src/utils/common.tsx b/wondrous-bot-admin/src/utils/common.tsx index c68c052c62..2dfd6bacc9 100644 --- a/wondrous-bot-admin/src/utils/common.tsx +++ b/wondrous-bot-admin/src/utils/common.tsx @@ -71,30 +71,30 @@ export const camelToSnake = (str) => { export const constructExplorerRedirectUrl = (chain, txHash) => `${CHAIN_TO_EXPLORER_URL[chain]}/tx/${txHash}`; -export const constructRewards = ({rewards}) => { +export const constructRewards = ({ rewards }) => { return rewards?.map((reward) => { - if(reward.type === 'points') { + if (reward.type === "points") { return reward; } - if(reward.type === PAYMENT_OPTIONS.TOKEN) { + if (reward.type === PAYMENT_OPTIONS.TOKEN) { return { type: reward?.paymentMethod?.name, value: reward?.amount, - } + }; } - if(reward.type === PAYMENT_OPTIONS.DISCORD_ROLE) { + if (reward.type === PAYMENT_OPTIONS.DISCORD_ROLE) { return { - type: 'Discord Role', + type: "Discord Role", value: reward?.discordRewardData?.discordRoleName || null, - } + }; } - if(reward.type === PAYMENT_OPTIONS.POAP) { + if (reward.type === PAYMENT_OPTIONS.POAP) { return { - type: 'POAP', + type: "POAP", value: reward?.poapRewardData?.name || null, - } + }; } - }) + }); }; export const filterToDates = (value) => { @@ -121,3 +121,25 @@ export const filterToDates = (value) => { endDate: moment().utcOffset(0).endOf("day").toISOString(), }; }; + +export const getYoutubeChannelId = (url) => { + // Extract channel ID from the second format: https://www.youtube.com/channel/channelId + const regex1 = /^https:\/\/www\.youtube\.com\/channel\/([^\?]+)/; + const match1 = url.match(regex1); + if (match1 && match1.length >= 2) { + return { channelId: match1[1] }; + } + // Extract channel ID from the first format: https://www.youtube.com/@channelName + + const regex2 = /^https:\/\/www\.youtube\.com\/@([^\?]+)/; + const match2 = url.match(regex2); + if (match2 && match2.length >= 2) { + return { channelHandle: match2[1] }; + } +}; + +export const getWeb3ConnectUrl = ({ telegramUserId }) => { + const baseUrl = getBaseUrl(); + const link = `${baseUrl}/wallet/connect?telegramUserId=${telegramUserId}`; + return link; +}; diff --git a/wondrous-bot-admin/src/utils/constants.tsx b/wondrous-bot-admin/src/utils/constants.tsx index 210a18a713..1f4756a93b 100644 --- a/wondrous-bot-admin/src/utils/constants.tsx +++ b/wondrous-bot-admin/src/utils/constants.tsx @@ -316,3 +316,45 @@ export const TUTORIALS = { COMMUNITIES_QUESTS_PAGE_GUIDE: "communities_quests_page_guide", COMMUNITIES_QUEST: "communities_quest", }; + +export const DEFAULT_BANNER_IMAGES = { + QUEST: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/d1dde3c6-ec7b-47d0-7038-5f0559af3300/public', + LEVEL: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/fce99bf4-8658-41cc-4d62-6797e37fe700/public', + LEADERBOARD: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/2379966b-c3ab-498c-d290-cf0826928100/public', + QUEST_APPROVED: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/1664bce7-ae62-471d-dcc8-c12ea97ef400/public', + QUEST_COMPLETED: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/2f3f3cee-37cf-4988-7ecc-721ec1294f00/public', + QUEST_SUBMITTED: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/0b69e6ff-801c-4596-c9be-42c0cd6d4800/public', + QUEST_READY_TO_SUBMIT: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/0b69e6ff-801c-4596-c9be-42c0cd6d4800/public', + START_QUEST: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/45fd3534-6756-445d-4d17-19b277fd7d00/public', + ONBOARD_ME: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/d96083c6-2250-4780-d492-3b27d702dc00/public', + MY_SUBMISSION: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/955c330d-947d-4a6b-8005-2319b36ee800/public', + QUESTION_MARK: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/272fca8c-f320-4578-0e8a-2eff794d3f00/public', + ATTACHMENT_REQUIRED: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/73b4752f-d9a5-4c79-8151-5989c8b1fa00/public', + QUEST_STEP_TWITTER: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/89ebf640-014a-45e2-319c-fe2b530c8900/public', + QUEST_STEP_DISCORD: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/a64a25dd-3d03-40a2-ac40-02c2017c8300/public', + QUEST_STEP_SNAPSHOT: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/280a3673-93a0-4be1-0cdf-2c0a7c88ab00/public', + SHOW_QUESTS_1: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/28218faf-0823-4db9-4f6a-3cd4db1ace00/public', + SHOW_QUESTS_2: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/61f360a2-3c12-4110-4537-4f1262bf8500/public', + SHOW_LEADERBOARD: + 'https://imagedelivery.net/Nf8NSpw7AwOfpJLL_UgXaw/4737f05c-0a90-4526-be43-3f18fc9faf00/public', +}; + + +export const SELECT_STEP_TYPES = ['multiple_quiz', 'single_quiz']; diff --git a/wondrous-bot-admin/src/utils/context/TakeQuestContext.tsx b/wondrous-bot-admin/src/utils/context/TakeQuestContext.tsx new file mode 100644 index 0000000000..a2b5bf7053 --- /dev/null +++ b/wondrous-bot-admin/src/utils/context/TakeQuestContext.tsx @@ -0,0 +1,5 @@ +import {createContext} from 'react'; + +const TakeQuestContext = createContext(null); + +export default TakeQuestContext; diff --git a/wondrous-bot-admin/src/utils/hooks.tsx b/wondrous-bot-admin/src/utils/hooks.tsx index 20208eabc6..1e1ff4c04f 100644 --- a/wondrous-bot-admin/src/utils/hooks.tsx +++ b/wondrous-bot-admin/src/utils/hooks.tsx @@ -4,6 +4,7 @@ import { useLazyQuery } from "@apollo/client"; import { IS_ORG_USERNAME_TAKEN } from "graphql/queries"; import SubscriptionContext from "./context/SubscriptionContext"; import PaywallContext from "./context/PaywallContext"; +import TakeQuestContext from "./context/TakeQuestContext"; const useAlerts = () => { const { @@ -55,3 +56,5 @@ export default useAlerts; export const useSubscription = () => useContext(SubscriptionContext); export const usePaywall = () => useContext(PaywallContext); + +export const useTakeQuest = () => useContext(TakeQuestContext) \ No newline at end of file From b5e99ed755945fa015b8147696c88d653230929f Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Mon, 28 Aug 2023 22:00:56 +0300 Subject: [PATCH 12/31] revert commented code --- .../src/components/AddFormEntity/index.tsx | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/wondrous-bot-admin/src/components/AddFormEntity/index.tsx b/wondrous-bot-admin/src/components/AddFormEntity/index.tsx index bbbea4f7a0..02606fcaa2 100644 --- a/wondrous-bot-admin/src/components/AddFormEntity/index.tsx +++ b/wondrous-bot-admin/src/components/AddFormEntity/index.tsx @@ -127,21 +127,21 @@ const AddFormEntity = ({ steps, setSteps, stepCache, handleRemove, refs, setRemo const handleChangeType = (type, order, idx) => { if (!type) return; - // if ( - // (plan === PricingOptionsTitle.Basic || plan === PricingOptionsTitle.Hobby) && - // (type === TYPES.SUBSCRIBE_YT_CHANNEL || type === TYPES.LIKE_YT_VIDEO || type === TYPES.CUSTOM_ONCHAIN_ACTION) - // ) { - // setPaywall(true); - // setPaywallMessage("This feature is only available on the Pro plan and above"); - // return; - // } - // if ( - // (plan === PricingOptionsTitle.Premium || plan === PricingOptionsTitle.Ecosystem) && - // type === TYPES.CUSTOM_ONCHAIN_ACTION - // ) { - // setOpenEcosystemDialog(true); - // return; - // } + if ( + (plan === PricingOptionsTitle.Basic || plan === PricingOptionsTitle.Hobby) && + (type === TYPES.SUBSCRIBE_YT_CHANNEL || type === TYPES.LIKE_YT_VIDEO || type === TYPES.CUSTOM_ONCHAIN_ACTION) + ) { + setPaywall(true); + setPaywallMessage("This feature is only available on the Pro plan and above"); + return; + } + if ( + (plan === PricingOptionsTitle.Premium || plan === PricingOptionsTitle.Ecosystem) && + type === TYPES.CUSTOM_ONCHAIN_ACTION + ) { + setOpenEcosystemDialog(true); + return; + } setErrors((prev) => { return { ...prev, From fdd909ae3fa2bd96e6f4484391bae21b33f29551 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Mon, 28 Aug 2023 22:01:55 +0300 Subject: [PATCH 13/31] remove console --- wondrous-bot-admin/src/components/QuestSteps/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index e1f5e5ac74..67fbf2a122 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -147,7 +147,6 @@ const QuestStepsList = () => { const handleSubmit = async () => { const questSubmissions = []; - console.log(responses, "RESPONSES"); for (const step of data?.getQuestById.steps) { const answer = responses[step.id]; const isQuestSkipped = responses[step.id] === null; From e6e428dfee27d509f3dbc17488a9174e79668f22 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Mon, 28 Aug 2023 22:21:30 +0300 Subject: [PATCH 14/31] add media --- .../src/components/QuestSteps/SubmitQuest.tsx | 4 ++- .../src/components/QuestSteps/index.tsx | 31 +++++++++++++++++-- .../src/components/QuestSteps/styles.tsx | 2 +- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx b/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx index a458cce9b7..cc913a9752 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx @@ -32,7 +32,9 @@ const SubmitQuest = ({ Do you want to submit your response? - + Edit Responses Promise.all( @@ -48,6 +51,12 @@ const COMPONENTS_CONFIG: any = { [TYPES.DATA_COLLECTION]: () => null, }; +const IMAGES_CONFIG = { + [TYPES.SNAPSHOT_PROPOSAL_VOTE]: DEFAULT_BANNER_IMAGES.QUEST_STEP_SNAPSHOT, + [TYPES.SNAPSHOT_SPACE_VOTE]: DEFAULT_BANNER_IMAGES.QUEST_STEP_SNAPSHOT, + [TYPES.ATTACHMENTS]: DEFAULT_BANNER_IMAGES.ATTACHMENT_REQUIRED, +}; + const QuestStep = ({ step, value, isActive, nextStepId, isWebView = false }) => { const Component: React.FC = COMPONENTS_CONFIG[step?.type]; const [isActionDisabled, setIsActionDisabled] = useState(false); @@ -72,6 +81,7 @@ const QuestStep = ({ step, value, isActive, nextStepId, isWebView = false }) => )} renderBody={() => ( + {IMAGES_CONFIG[step.type] ? : null} onChange={(value) => onChange({ id: step.id, value })} placeholder="Enter answer" /> + {step?.media ? ( + + {step?.media?.map((item) => { + return ( + + + + ); + })} + + ) : null} )} /> diff --git a/wondrous-bot-admin/src/components/QuestSteps/styles.tsx b/wondrous-bot-admin/src/components/QuestSteps/styles.tsx index c20b121af3..e32217f661 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/styles.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/styles.tsx @@ -1,6 +1,6 @@ import styled from "styled-components"; export const Image = styled.img` - height: 81px; width: auto; + max-height: 200px; `; From e4347f1ab05a3a620f01ef0a682de1f3a872d3fd Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Tue, 29 Aug 2023 17:30:11 +0300 Subject: [PATCH 15/31] more edit stuff --- .../CreateTemplate/PanelComponent.tsx | 7 +- .../CreateTemplate/RewardComponent.tsx | 16 +- .../src/components/CreateTemplate/styles.tsx | 2 +- .../components/QuestSteps/EditModal/index.tsx | 162 ++++++++++++++++ .../QuestSteps/QuestStepComponent.tsx | 113 +++++++++++ .../components/QuestSteps/StepModal/index.tsx | 66 +++++-- .../QuestSteps/Steps/Attachment.tsx | 2 +- .../QuestSteps/Steps/OptionSelect.tsx | 4 +- .../QuestSteps/Steps/VerifyButton.tsx | 35 +--- .../src/components/QuestSteps/SubmitQuest.tsx | 168 ++++++++++++++-- .../src/components/QuestSteps/index.tsx | 182 ++++++------------ .../components/ViewQuestResults/styles.tsx | 2 +- wondrous-bot-admin/src/utils/constants.tsx | 5 +- 13 files changed, 566 insertions(+), 198 deletions(-) create mode 100644 wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx create mode 100644 wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx diff --git a/wondrous-bot-admin/src/components/CreateTemplate/PanelComponent.tsx b/wondrous-bot-admin/src/components/CreateTemplate/PanelComponent.tsx index b627beed8f..dc7605638d 100644 --- a/wondrous-bot-admin/src/components/CreateTemplate/PanelComponent.tsx +++ b/wondrous-bot-admin/src/components/CreateTemplate/PanelComponent.tsx @@ -1,12 +1,12 @@ import { Divider, Grid } from '@mui/material'; import { Panel, CampaignOverviewTitle } from './styles'; -const PanelComponent = ({ renderHeader, renderBody, panelProps = {} }) => ( +const PanelComponent = ({ renderHeader, renderBody, panelProps = {}, gridSx={} }) => ( - {renderHeader()} - + {renderHeader?.()} + {renderHeader ? : null} ( bgcolor="white" padding='24px 14px' borderRadius="16px" + {...gridSx} > {renderBody()} diff --git a/wondrous-bot-admin/src/components/CreateTemplate/RewardComponent.tsx b/wondrous-bot-admin/src/components/CreateTemplate/RewardComponent.tsx index 2e455e4f14..3a951fc07e 100644 --- a/wondrous-bot-admin/src/components/CreateTemplate/RewardComponent.tsx +++ b/wondrous-bot-admin/src/components/CreateTemplate/RewardComponent.tsx @@ -427,13 +427,15 @@ const RewardComponent = ({ rewards, setQuestSettings }) => { }} background={PAYMENT_OPTIONS.TOKEN === rewardType ? "#BFB4F3" : "#FFFFF"} onClick={() => { - if (plan === PricingOptionsTitle.Basic) { - setPaywall(true); - setPaywallMessage("This reward option is not available under the basic plan."); - return; - } else { - setRewardType(PAYMENT_OPTIONS.TOKEN); - } + setRewardType(PAYMENT_OPTIONS.TOKEN); + + // if (plan === PricingOptionsTitle.Basic) { + // setPaywall(true); + // setPaywallMessage("This reward option is not available under the basic plan."); + // return; + // } else { + // setRewardType(PAYMENT_OPTIONS.TOKEN); + // } }} > Token reward diff --git a/wondrous-bot-admin/src/components/CreateTemplate/styles.tsx b/wondrous-bot-admin/src/components/CreateTemplate/styles.tsx index 2768e2738a..032983181b 100644 --- a/wondrous-bot-admin/src/components/CreateTemplate/styles.tsx +++ b/wondrous-bot-admin/src/components/CreateTemplate/styles.tsx @@ -4,7 +4,7 @@ import { TextareaAutosize } from "@mui/base"; export const Panel = styled(Grid)` && { - filter: drop-shadow(0px 4px 34px rgba(0, 0, 0, 0.24)); + filter: ${({ filter = "drop-shadow(0px 4px 34px rgba(0, 0, 0, 0.24))" }) => filter}; border-radius: 16px; background: #f7f7f7; width: 100%; diff --git a/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx new file mode 100644 index 0000000000..8808aa012e --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx @@ -0,0 +1,162 @@ +import { Box, Divider, Grid, Typography } from "@mui/material"; +import { BotIcon } from "assets/botIcon"; +import PanelComponent from "components/CreateTemplate/PanelComponent"; +import { StyledCheckbox } from "components/PaymentLedger/styles"; +import { SharedSecondaryButton } from "components/Shared/styles"; +import { StyledContent, StyledViewQuestResults } from "components/ViewQuestResults/styles"; +import { useMemo, useState } from "react"; +import { DATA_COLLECTION_TYPES, INTERESTS, SELECT_TYPES, SKILLS, TYPES } from "utils/constants"; +import { useTakeQuest } from "utils/hooks"; +import { Media } from "../Steps/Attachment"; +import QuestStepComponent from "../QuestStepComponent"; + +const StepContent = ({ response, stepType, dataCollectionType }) => { + const contentTypes = [TYPES.TEXT_FIELD, TYPES.NUMBER]; + + const linkVisits = [ + TYPES.LINK_CLICK, + TYPES.FOLLOW_TWITTER, + TYPES.LIKE_TWEET, + TYPES.LIKE_YT_VIDEO, + TYPES.RETWEET, + TYPES.TWEET_WITH_PHRASE, + TYPES.VERIFY_TOKEN_HOLDING, + TYPES.SUBSCRIBE_YT_CHANNEL, + TYPES.SNAPSHOT_SPACE_VOTE, + TYPES.SNAPSHOT_PROPOSAL_VOTE, + ]; + + if (!response) { + return ( + + Step was skipped + + ); + } + + if (contentTypes?.includes(stepType)) { + return ( + + {response} + + ); + } + if (linkVisits.includes(stepType)) { + return ( + + + Verified URL visit + + ); + } + + if (SELECT_TYPES.includes(stepType)) { + return ( + + {response?.map((value, idx) => ( + {value} + ))} + + ); + } + if (stepType === TYPES.ATTACHMENTS) { + return ( + + {response?.map((media, idx) => { + return ; + })} + + ); + } + if (stepType === TYPES.DATA_COLLECTION) { + const isSkill = dataCollectionType === DATA_COLLECTION_TYPES.SKILLS; + const isInterest = dataCollectionType === DATA_COLLECTION_TYPES.INTERESTS; + return ( + + {response?.map((option, idx) => { + let label = option; + if (isSkill) { + label = SKILLS[option] || option; + } + if (isInterest) { + label = INTERESTS[option] || option; + } + return {label}; + })} + + ); + } + return null; +}; + +const QuestStepsList = ({ steps, responses, setEditStepId }) => { + const { handleSubmit } = useTakeQuest(); + return ( + <> + { + return ( + + + Confirm your Answers + + + ); + }} + renderBody={() => ( + <> + + {steps?.map((step, idx) => { + const response = responses[step?.id]; + return ( + <> + + {idx === steps.length - 1 ? null : } + + ); + })} + + + )} + /> + Submit + + ); +}; + +const EditModal = ({ responses }) => { + const { quest } = useTakeQuest(); + const steps = quest?.steps; + const [editStepId, setEditStepId] = useState(null); + + const stepToEdit = useMemo(() => { + if (editStepId) { + return steps?.find((step) => step.id === editStepId); + } + return null; + }, [editStepId]); + console.log(stepToEdit, "step to edit", editStepId); + return ; +}; + +export default EditModal; diff --git a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx new file mode 100644 index 0000000000..5007e5ccc3 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx @@ -0,0 +1,113 @@ +import { Grid, Typography, Box } from "@mui/material"; +import PanelComponent from "components/CreateTemplate/PanelComponent"; +import SafeImage from "components/SafeImage"; +import { useState } from "react"; +import { useTakeQuest } from "utils/hooks"; +import { StepModal } from "./StepModal"; +import { TYPES, DEFAULT_BANNER_IMAGES } from "utils/constants"; +import { StepTextField } from "./Steps"; +import AttachmentType from "./Steps/Attachment"; +import OptionSelect from "./Steps/OptionSelect"; +import { VerifyButton } from "./Steps/VerifyButton"; +import { Image } from "./styles"; + +const COMPONENTS_CONFIG: any = { + [TYPES.TEXT_FIELD]: StepTextField, + [TYPES.MULTI_QUIZ]: OptionSelect, + [TYPES.SINGLE_QUIZ]: OptionSelect, + [TYPES.NUMBER]: (props) => , + [TYPES.ATTACHMENTS]: AttachmentType, + [TYPES.LINK_CLICK]: VerifyButton, + [TYPES.SUBSCRIBE_YT_CHANNEL]: VerifyButton, + [TYPES.LIKE_YT_VIDEO]: VerifyButton, + [TYPES.SNAPSHOT_PROPOSAL_VOTE]: VerifyButton, + [TYPES.SNAPSHOT_SPACE_VOTE]: VerifyButton, + + [TYPES.VERIFY_TOKEN_HOLDING]: VerifyButton, + [TYPES.DATA_COLLECTION]: () => null, +}; + +const IMAGES_CONFIG = { + [TYPES.SNAPSHOT_PROPOSAL_VOTE]: DEFAULT_BANNER_IMAGES.QUEST_STEP_SNAPSHOT, + [TYPES.SNAPSHOT_SPACE_VOTE]: DEFAULT_BANNER_IMAGES.QUEST_STEP_SNAPSHOT, + [TYPES.ATTACHMENTS]: DEFAULT_BANNER_IMAGES.ATTACHMENT_REQUIRED, +}; + +const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = false }) => { + const Component: React.FC = COMPONENTS_CONFIG[step?.type]; + const [isActionDisabled, setIsActionDisabled] = useState(false); + const { onChange, isEditMode } = useTakeQuest(); + if (!isActive || !step) return null; + if (Component) { + return ( + ( + + + Quest Portal + + + ) + } + renderBody={() => ( + + {IMAGES_CONFIG[step.type] ? : null} + onChange({ id: step.id, value })} + placeholder="Enter answer" + /> + {step?.media ? ( + + {step?.media?.map((item) => { + return ( + + + + ); + })} + + ) : null} + + )} + /> + ); + } + return null; +}; + +export default QuestStepComponent; diff --git a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx index 45df96addd..785d0f31c3 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx @@ -2,10 +2,44 @@ import { Grid, Box, Typography, ButtonBase } from "@mui/material"; import { BotIcon } from "assets/botIcon"; import { SharedSecondaryButton } from "components/Shared/styles"; import { StyledViewQuestResults } from "components/ViewQuestResults/styles"; +import { useMemo } from "react"; +import { TYPES } from "utils/constants"; import { useTakeQuest } from "utils/hooks"; +const PromptComponent = ({ step }) => { + const snapshotVoteTimes = step?.additionalData?.snapshotVoteTimes; + + const content = useMemo(() => { + if (step.prompt) { + return step.prompt; + } + if(step.type === TYPES.LINK_CLICK) { + return 'Click on the link below to verify' + } + if(step.type === TYPES.LIKE_YT_VIDEO) { + return 'Verify YouTube Like' + } + if(step.type === TYPES.SUBSCRIBE_YT_CHANNEL) { + return 'Verify YouTube Subscription' + } + if(step.type === TYPES.SNAPSHOT_PROPOSAL_VOTE) { + return 'Please vote on this proposal' + } + if(step.type === TYPES.SNAPSHOT_SPACE_VOTE) { + return `Please vote in this space at least ${snapshotVoteTimes} times` + } + return null; + }, [step.prompt, step.type, snapshotVoteTimes]); + + return ( + + {content} + + ); +}; + export const StepModal = ({ children, step, disabled, nextStepId }) => { - const { nextStep, handleSubmit } = useTakeQuest(); + const { nextStep, isEditMode } = useTakeQuest(); return ( @@ -14,25 +48,25 @@ export const StepModal = ({ children, step, disabled, nextStepId }) => { - - {step.prompt} - + {children} - - - Next - - {step?.required ? null : ( - - - Skip Step - - - )} - + {isEditMode ? null : ( + + + Next + + {step?.required ? null : ( + + + Skip Step + + + )} + + )}
); }; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/Attachment.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/Attachment.tsx index 81df66cf75..d9809f5da7 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/Attachment.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/Attachment.tsx @@ -15,7 +15,7 @@ import { isVideo } from "utils/media"; import VideoPlayer from "components/Shared/SubmissionMedia/VideoPlayer"; import { Filename } from "components/Shared/SubmissionMedia/styles"; -const Media = ({ file }) => { +export const Media = ({ file }) => { if (file.type?.includes("image")) { return ; } diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx index aff28e4ab0..0f650088d7 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx @@ -5,6 +5,7 @@ import { useMemo } from "react"; import { TYPES } from "utils/constants"; export const OptionSelect = ({ step, onChange, value, setIsActionDisabled, isActionDisabled }) => { + console.log(value, 'VALUE') const opacity = useMemo(() => { if (step.type === TYPES.SINGLE_QUIZ && value && value.length > 0) { return 0.3; @@ -78,6 +79,7 @@ export const OptionSelect = ({ step, onChange, value, setIsActionDisabled, isAct bgcolor={"#2A8D5C"} height="22px" width="22px" + checked={value?.includes(option.text)} disabled={step.type === TYPES.SINGLE_QUIZ && value?.length > 0 && !value.includes(option.text)} onChange={(e) => handleCheckboxChange(e, option.text)} /> @@ -88,7 +90,7 @@ export const OptionSelect = ({ step, onChange, value, setIsActionDisabled, isAct ); })} {isCorrect !== null && - value?.length && + !!value?.length && (isCorrect ? null : Please select only the correct options)}
); diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx index 50bf4ac166..c9d171785a 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx @@ -1,5 +1,5 @@ import { useLazyQuery, useMutation } from "@apollo/client"; -import { CircularProgress, Grid, Typography } from "@mui/material"; +import { Box, CircularProgress, Grid, Typography } from "@mui/material"; import { Label } from "components/AddFormEntity/components/styles"; import Spinner from "components/Shared/Spinner"; import { ErrorText, SharedSecondaryButton } from "components/Shared/styles"; @@ -23,30 +23,21 @@ const LinkComponent = ({ loading, link, onClick, - label = "Click on the link below to verify", - linkText = "Visit Link", + label = "Click to verify", + linkText = "Verify", error = null, }) => { return ( - <> + {loading ? : null} - - - {linkText} - + + {linkText} {error ? {error} : null} - + ); }; @@ -63,7 +54,7 @@ const GoogleVerify = ({ telegramUserId, callback }) => { ); }; -const Web3Connect = ({ telegramUserId, callback }) => { +export const Web3Connect = ({ telegramUserId, callback }) => { const handleClick = () => { return callback?.(); }; @@ -228,13 +219,11 @@ const YoutubeButton = ({ step, cmtyUser, startCmtyUserPolling, stopCmtyUserPolli return handleVerifySubscription(); }; - const label = step.type === TYPES.LIKE_YT_VIDEO ? "Verify YouTube Like" : "Verify YouTube Subscription"; return ( { diff --git a/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx b/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx index cc913a9752..a231d2f56e 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx @@ -2,11 +2,153 @@ import { Box, Grid, Typography } from "@mui/material"; import PanelComponent from "components/CreateTemplate/PanelComponent"; import { DEFAULT_BANNER_IMAGES } from "utils/constants"; import { Image } from "./styles"; -import { SharedSecondaryButton } from "components/Shared/styles"; +import { ErrorText, SharedSecondaryButton } from "components/Shared/styles"; +import { useTakeQuest } from "utils/hooks"; +import { GET_QUEST_REWARDS } from "graphql/queries"; +import { useLazyQuery } from "@apollo/client"; +import { useEffect, useMemo } from "react"; +import { NFTIcon, PointsIcon } from "components/Icons/Rewards"; +import { TextLabel } from "components/ViewQuest/styles"; -const SubmitQuest = ({ - handleSubmit -}) => { +const Body = ({ header, subHeader, renderComponents = null }) => { + return ( + <> + + {header} + + + {subHeader} + + + + {renderComponents?.()} + + ); +}; + +const SubmitBodyComponent = ({ handleSubmit }) => { + const { setIsEditMode } = useTakeQuest(); + return ( + ( + + setIsEditMode(true)} $reverse> + Edit Responses + + Submit Quest + + )} + /> + ); +}; + +const SubmittedQuestRewards = ({ quest }) => { + const [getQuestRewards, { data: questRewardsData }] = useLazyQuery(GET_QUEST_REWARDS); + + useEffect(() => { + getQuestRewards({ + variables: { + questId: quest.id, + }, + }); + }, [quest?.requireReview]); + + const rewards = useMemo(() => { + let roles = [ + { + label: `${quest?.pointReward} points`, + icon: PointsIcon, + }, + ]; + let questRewards = + questRewardsData?.getQuestRewards?.map((reward) => { + if (reward.type === "token") { + return { + label: `Token: ${reward.amount} ${reward?.paymentMethod?.name || reward?.paymentMethod?.contractAddress}`, + icon: reward?.paymentMethod?.type?.toLowerCase() === "erc20" ? PointsIcon : NFTIcon, + subLabel: "These will be sent later to your wallet", + }; + } + if (reward.type === "poap") { + return { + label: `POAP: ${reward.poapRewardData?.name}`, + icon: NFTIcon, + subComponent: () => ( + + + See it + + + ), + }; + } + }) || []; + return [...roles, ...questRewards]; + }, [quest, questRewardsData]); + + return ( + <> + + Rewards + + + {rewards?.map((reward, idx) => ( + + + {reward && } + {reward?.label} + + + {reward?.subLabel ? ( + + {reward?.subLabel} + + ) : null} + {reward.subComponent?.()} + + + ))} + + + ); +}; + +const SubmittedQuestBody = () => { + const { quest } = useTakeQuest(); + + const subHeader = quest?.requireReview + ? "Your submission has been sent for review" + : "Your submission has been approved"; + + return ( + <> + + {quest?.requireReview === false ? : null} + Close + + ); +}; + +const SubmitQuest = ({ handleSubmit, submittedQuestData, errorComponents = null }) => { return ( ( @@ -25,22 +167,8 @@ const SubmitQuest = ({ )} renderBody={() => ( - - Ready to submit the quest? - - - Do you want to submit your response? - - - - - Edit Responses - Submit Quest - + {submittedQuestData ? : } + {errorComponents?.()} )} /> diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index fa23d75d0a..ed68262622 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -1,129 +1,47 @@ -import { DEFAULT_BANNER_IMAGES, SELECT_STEP_TYPES, TYPES } from "utils/constants"; -import { StepTextField } from "./Steps"; -import { Box, Grid, Typography } from "@mui/material"; -import PanelComponent from "components/CreateTemplate/PanelComponent"; +import { SELECT_TYPES, TYPES } from "utils/constants"; +import { Grid } from "@mui/material"; import { useEffect, useState } from "react"; -import { StepModal } from "./StepModal"; -import OptionSelect from "./Steps/OptionSelect"; -import AttachmentType from "./Steps/Attachment"; -import { VerifyButton } from "./Steps/VerifyButton"; +import { Web3Connect } from "./Steps/VerifyButton"; import { GET_QUEST_BY_ID, USER_CAN_START_QUEST } from "graphql/queries"; import { useLazyQuery, useMutation } from "@apollo/client"; import { useParams } from "react-router-dom"; -import { transformAndUploadMedia } from "utils/media"; import TakeQuestContext from "utils/context/TakeQuestContext"; -import { useTakeQuest } from "utils/hooks"; import SubmitQuest from "./SubmitQuest"; import { SUBMIT_QUEST } from "graphql/mutations"; -import { Image } from "./styles"; -import SubmissionMedia from "components/Shared/SubmissionMedia"; -import SafeImage from "components/SafeImage"; +import { ErrorText } from "components/Shared/styles"; +import EditModal from "./EditModal"; +import QuestStepComponent from "./QuestStepComponent"; -const handleMediaUpload = async (mediaUploads) => - Promise.all( - mediaUploads.map(async (file) => { - try { - const { filename, fileType } = await transformAndUploadMedia({ file }); - return { - uploadSlug: filename, - type: fileType, - name: file.name, - }; - } catch (error) { - return null; - } - }) - ); - -const COMPONENTS_CONFIG: any = { - [TYPES.TEXT_FIELD]: StepTextField, - [TYPES.MULTI_QUIZ]: OptionSelect, - [TYPES.SINGLE_QUIZ]: OptionSelect, - [TYPES.NUMBER]: (props) => , - [TYPES.ATTACHMENTS]: AttachmentType, - [TYPES.LINK_CLICK]: VerifyButton, - [TYPES.SUBSCRIBE_YT_CHANNEL]: VerifyButton, - [TYPES.LIKE_YT_VIDEO]: VerifyButton, - - [TYPES.SNAPSHOT_PROPOSAL_VOTE]: VerifyButton, - [TYPES.SNAPSHOT_SPACE_VOTE]: VerifyButton, - [TYPES.VERIFY_TOKEN_HOLDING]: VerifyButton, - [TYPES.DATA_COLLECTION]: () => null, -}; +const ErrorHelpers = ({ error, callback, telegramUserId }) => { + const errorCode = error?.graphQLErrors?.[0]?.extensions?.errorCode; + const errorMessage = error?.graphQLErrors?.[0]?.extensions?.message; -const IMAGES_CONFIG = { - [TYPES.SNAPSHOT_PROPOSAL_VOTE]: DEFAULT_BANNER_IMAGES.QUEST_STEP_SNAPSHOT, - [TYPES.SNAPSHOT_SPACE_VOTE]: DEFAULT_BANNER_IMAGES.QUEST_STEP_SNAPSHOT, - [TYPES.ATTACHMENTS]: DEFAULT_BANNER_IMAGES.ATTACHMENT_REQUIRED, -}; + if (!error) return null; -const QuestStep = ({ step, value, isActive, nextStepId, isWebView = false }) => { - const Component: React.FC = COMPONENTS_CONFIG[step?.type]; - const [isActionDisabled, setIsActionDisabled] = useState(false); - const { onChange } = useTakeQuest(); - if (!isActive) return null; - if (Component) { + if (errorCode === "no_active_wallet") { return ( - ( - - - Quest Portal - - - )} - renderBody={() => ( - - {IMAGES_CONFIG[step.type] ? : null} - onChange({ id: step.id, value })} - placeholder="Enter answer" - /> - {step?.media ? ( - - {step?.media?.map((item) => { - return ( - - - - ); - })} - - ) : null} - - )} - /> + <> + + There is a token reward with this quest! Please connect your wallet first and then click submit again. + + + ); } - return null; + if (errorMessage?.includes("You already minted a POAP for this drop")) { + return {errorMessage}; + } + return Something went wrong; }; const QuestStepsList = () => { let { id } = useParams(); - const [submitQuest] = useMutation(SUBMIT_QUEST); + const [submitQuest, { data: submittedQuestData, error }] = useMutation(SUBMIT_QUEST); const [activeStepId, setActiveStepId] = useState(null); const [responses, setResponses] = useState({}); const [showSubmitView, setShowSubmitView] = useState(false); - const [isEditMode, setIsEditMode] = useState(false); const webApp = (window as any)?.Telegram?.WebApp; @@ -190,7 +108,7 @@ const QuestStepsList = () => { content: answer, order: step.order, }); - } else if (SELECT_STEP_TYPES.includes(step.type)) { + } else if (SELECT_TYPES.includes(step.type)) { questSubmissions.push({ stepId: step.id, order: step.order, @@ -234,10 +152,12 @@ const QuestStepsList = () => { stepsData: questSubmissions, }; - const { data: submitQuestResultData } = await submitQuest({ - variables: submissionInput, - }); - + try { + const { data: submitQuestResultData } = await submitQuest({ + variables: submissionInput, + }); + if (isEditMode) setIsEditMode(false); + } catch (error) {} //TODO: handle reward && next screen // const stepsSubmission = camelToSnakeArr(questSubmissions); // const submissionInput = { @@ -254,6 +174,10 @@ const QuestStepsList = () => { const currentStepIdx = steps?.findIndex((step) => step.id === activeStepId); const nextStepId = steps[currentStepIdx + 1]?.id; + if (isEditMode) { + setIsEditMode(false); + return setShowSubmitView(true); + } if (!nextStepId) { return setShowSubmitView(true); } @@ -273,24 +197,38 @@ const QuestStepsList = () => { handleSubmit, telegramUser: webApp?.initDataUnsafe?.user, isWebView: webApp?.isWebView, + quest: data?.getQuestById, + setIsEditMode, + setShowSubmitView, + isEditMode, }} > - {showSubmitView ? ( - + {showSubmitView && !isEditMode ? ( + ( + + )} + /> ) : ( <> - {data?.getQuestById?.steps?.map((step, idx) => { - return ( - - ); - })} + {isEditMode ? ( + + ) : ( + data?.getQuestById?.steps?.map((step, idx) => { + return ( + + ); + }) + )} )} diff --git a/wondrous-bot-admin/src/components/ViewQuestResults/styles.tsx b/wondrous-bot-admin/src/components/ViewQuestResults/styles.tsx index 2ea66f33b8..9a7c55d4c8 100644 --- a/wondrous-bot-admin/src/components/ViewQuestResults/styles.tsx +++ b/wondrous-bot-admin/src/components/ViewQuestResults/styles.tsx @@ -66,6 +66,6 @@ export const StyledContent = styled(Typography)` font-weight: 500; font-size: 14px; line-height: 24px; - color: #767676; + color: ${({color = "#767676"}) => color}; } `; diff --git a/wondrous-bot-admin/src/utils/constants.tsx b/wondrous-bot-admin/src/utils/constants.tsx index a76583eb20..7045c6114a 100644 --- a/wondrous-bot-admin/src/utils/constants.tsx +++ b/wondrous-bot-admin/src/utils/constants.tsx @@ -360,7 +360,10 @@ export const DEFAULT_BANNER_IMAGES = { }; -export const SELECT_STEP_TYPES = ['multiple_quiz', 'single_quiz']; +export const TEXT_TYPES = [TYPES.TEXT_FIELD, TYPES.NUMBER]; + +export const SELECT_TYPES = [TYPES.MULTI_QUIZ, TYPES.SINGLE_QUIZ]; + export const CUSTOM_INTEGRATIONS = { // LIFI "58318954576216128": { From 8686b8c7dfe0b57625457f9432b2660242e9f35f Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Tue, 29 Aug 2023 18:04:06 +0300 Subject: [PATCH 16/31] media stuff --- .../QuestSteps/Steps/VerifyButton.tsx | 28 +++++------ .../src/components/QuestSteps/SubmitQuest.tsx | 2 +- .../src/components/QuestSteps/index.tsx | 49 ++++++++++++------- .../src/graphql/queries/media.ts | 9 ++++ wondrous-bot-admin/src/utils/media/index.tsx | 32 +++++++++++- 5 files changed, 83 insertions(+), 37 deletions(-) diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx index c9d171785a..0af5b6c65f 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx @@ -1,5 +1,5 @@ -import { useLazyQuery, useMutation } from "@apollo/client"; -import { Box, CircularProgress, Grid, Typography } from "@mui/material"; +import { useLazyQuery } from "@apollo/client"; +import { Box, Grid } from "@mui/material"; import { Label } from "components/AddFormEntity/components/styles"; import Spinner from "components/Shared/Spinner"; import { ErrorText, SharedSecondaryButton } from "components/Shared/styles"; @@ -13,27 +13,24 @@ import { VERIFY_YT_SUBSCRIPTION, } from "graphql/queries"; import { getGoogleOauthUrl } from "pages/oauth/google/callback"; -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo } from "react"; import { getYouTubeVideoId } from "services/validators/customValidation"; import { getBaseUrl, getWeb3ConnectUrl, getYoutubeChannelId } from "utils/common"; import { TYPES } from "utils/constants"; import { useTakeQuest } from "utils/hooks"; -const LinkComponent = ({ - loading, - link, - onClick, - label = "Click to verify", - linkText = "Verify", - error = null, -}) => { +const LinkComponent = ({ loading, link, onClick, label = "Click to verify", linkText = "Verify", error = null }) => { return ( {loading ? : null} - + {linkText} {error ? {error} : null} @@ -237,7 +234,7 @@ const SnapshotButton = ({ step, cmtyUser, handleLinkClick, startCmtyUserPolling, const snapshotProposalLink = step?.additionalData?.snapshotProposalLink; const snapshotSpaceLink = step?.additionalData?.snapshotSpaceLink; const snapshotVoteTimes = step?.additionalData?.snapshotVoteTimes; - + const isProposalType = step.type === TYPES.SNAPSHOT_PROPOSAL_VOTE; const { onChange, nextStep } = useTakeQuest(); @@ -352,7 +349,6 @@ const SnapshotButton = ({ step, cmtyUser, handleLinkClick, startCmtyUserPolling, error={errorMessage} link={snapshotProposalLink || snapshotSpaceLink} onClick={onClick} - label={label} loading={loading || spaceLoading} /> ); diff --git a/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx b/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx index a231d2f56e..f8e348ce7a 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx @@ -2,7 +2,7 @@ import { Box, Grid, Typography } from "@mui/material"; import PanelComponent from "components/CreateTemplate/PanelComponent"; import { DEFAULT_BANNER_IMAGES } from "utils/constants"; import { Image } from "./styles"; -import { ErrorText, SharedSecondaryButton } from "components/Shared/styles"; +import { SharedSecondaryButton } from "components/Shared/styles"; import { useTakeQuest } from "utils/hooks"; import { GET_QUEST_REWARDS } from "graphql/queries"; import { useLazyQuery } from "@apollo/client"; diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index ed68262622..2b6e184ed8 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -11,6 +11,24 @@ import { SUBMIT_QUEST } from "graphql/mutations"; import { ErrorText } from "components/Shared/styles"; import EditModal from "./EditModal"; import QuestStepComponent from "./QuestStepComponent"; +import { transformAndUploadMedia, transformAndUploadTelegramMedia } from "utils/media"; + +const handleMediaUpload = async (mediaUploads) => +Promise.all( + mediaUploads.map(async (file) => { + try { + const { filename, fileType } = await transformAndUploadTelegramMedia({ file }); + return { + uploadSlug: filename, + type: fileType, + name: file.name, + }; + } catch (error) { + return null; + } + }) +); + const ErrorHelpers = ({ error, callback, telegramUserId }) => { const errorCode = error?.graphQLErrors?.[0]?.extensions?.errorCode; @@ -117,18 +135,18 @@ const QuestStepsList = () => { }); } else if (step.type === TYPES.ATTACHMENTS) { //TODO: fix upload media from web app , probably separate endpoint - // const stepsMedia = isQuestSkipped ? [null] : await handleMediaUpload(answer); - // console.log(stepsMedia, 'STEPS MEDIA') - // questSubmissions.push({ - // stepId: step.id, - // order: step.order, - // skipped: isQuestSkipped, - // attachments: isQuestSkipped ? null : stepsMedia.map((media) => ({ - // filename: media.name, - // type: media.type, - // uploadSlug: media.uploadSlug - // })) - // }) + const stepsMedia = isQuestSkipped ? [null] : await handleMediaUpload(answer); + console.log(stepsMedia, 'STEPS MEDIA') + questSubmissions.push({ + stepId: step.id, + order: step.order, + skipped: isQuestSkipped, + attachments: isQuestSkipped ? null : stepsMedia.map((media) => ({ + filename: media.name, + type: media.type, + uploadSlug: media.uploadSlug + })) + }) } else if ([TYPES.LIKE_YT_VIDEO, TYPES.SUBSCRIBE_YT_CHANNEL].includes(step.type)) { questSubmissions.push({ stepId: step.id, @@ -159,13 +177,6 @@ const QuestStepsList = () => { if (isEditMode) setIsEditMode(false); } catch (error) {} //TODO: handle reward && next screen - // const stepsSubmission = camelToSnakeArr(questSubmissions); - // const submissionInput = { - // quest_id: questId, - // telegram_user_id: ctx.from.id, - // telegram_username: ctx.from.username, - // steps_data: stepsSubmission - // }; }; const steps = data?.getQuestById?.steps || []; diff --git a/wondrous-bot-admin/src/graphql/queries/media.ts b/wondrous-bot-admin/src/graphql/queries/media.ts index a19fb2f117..43d30bca1e 100644 --- a/wondrous-bot-admin/src/graphql/queries/media.ts +++ b/wondrous-bot-admin/src/graphql/queries/media.ts @@ -23,3 +23,12 @@ export const GET_PREVIEW_FILE = gql` } } `; + + +export const GET_PRESIGNED_TELEGRAM_IMAGE_URL = gql` + query getTelegramPresignedFileUrl($filename: String!, $telegramUserId: String!) { + getTelegramPresignedFileUrl(filename: $filename, telegramUserId: $telegramUserId) { + url + } + } +`; \ No newline at end of file diff --git a/wondrous-bot-admin/src/utils/media/index.tsx b/wondrous-bot-admin/src/utils/media/index.tsx index 8f81f10680..e26cd0ce30 100644 --- a/wondrous-bot-admin/src/utils/media/index.tsx +++ b/wondrous-bot-admin/src/utils/media/index.tsx @@ -1,5 +1,5 @@ import apollo from 'services/apollo'; -import { GET_PRESIGNED_IMAGE_URL } from 'graphql/queries'; +import { GET_PRESIGNED_IMAGE_URL, GET_PRESIGNED_TELEGRAM_IMAGE_URL } from 'graphql/queries'; import { makeUniqueId } from '@apollo/client/utilities'; import { @@ -27,6 +27,28 @@ export const uploadMedia = async ({ filename, fileType, file }) => { } }; +export const uploadTelegramMedia = async ({ filename, fileType, file }) => { + const telegramUserId = (window as any)?.Telegram?.WebApp?.initDataUnsafe?.user?.id?.toString(); + try { + const apolloResult = await apollo.query({ + query: GET_PRESIGNED_TELEGRAM_IMAGE_URL, + variables: { + filename, + telegramUserId + }, + }); + const apiUrl = apolloResult.data.getPresignedFileUrl.url; + // TODO: parse filetype + const uploadResponse = await fetch(apiUrl, { + method: 'PUT', + body: file, + }); + // console.log('uploadResponse', uploadResponse, apiUrl) + } catch (error) { + console.error('error', JSON.stringify(error, null, 2)); + } +}; + export const getFilenameAndType = (result) => { const uriArr = result.split('/'); const filename = uriArr[uriArr.length - 1]; @@ -125,3 +147,11 @@ export const transformAndUploadMedia = async ({ file }) => { await uploadMedia(imageFile); return { ...imageFile }; }; + +export const transformAndUploadTelegramMedia = async ({ file }) => { + if (!file) return null; + + const imageFile = handleImageFile({ file, id: makeUniqueId('temp') }); + await uploadTelegramMedia(imageFile); + return { ...imageFile }; +}; From c3d578fbf384d2756d322d35872597201d314a71 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Tue, 29 Aug 2023 22:53:12 +0300 Subject: [PATCH 17/31] improvements --- .../src/components/QuestSteps/SubmitQuest.tsx | 16 ++++++++-------- .../src/components/QuestSteps/index.tsx | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx b/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx index f8e348ce7a..c1937bc527 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/SubmitQuest.tsx @@ -23,7 +23,7 @@ const Body = ({ header, subHeader, renderComponents = null }) => { {renderComponents?.()} @@ -117,14 +117,14 @@ const SubmittedQuestRewards = ({ quest }) => { {reward && } {reward?.label} - + {reward?.subLabel || reward?.subComponent ? {reward?.subLabel ? ( - + {reward?.subLabel} ) : null} - {reward.subComponent?.()} - + {reward.subComponent ? reward.subComponent() : null} + : null} ))}
@@ -133,17 +133,17 @@ const SubmittedQuestRewards = ({ quest }) => { }; const SubmittedQuestBody = () => { - const { quest } = useTakeQuest(); + const { quest, webApp } = useTakeQuest(); const subHeader = quest?.requireReview ? "Your submission has been sent for review" : "Your submission has been approved"; - + return ( <> {quest?.requireReview === false ? : null} - Close + webApp?.close()}>Close ); }; diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index 2b6e184ed8..579e6aee9f 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -78,6 +78,7 @@ const QuestStepsList = () => { if (!webApp?.initDataUnsafe?.user?.id) { return; } + webApp?.expand(); handleStart(); }, [webApp?.initDataUnsafe?.user?.id, webApp?.initDataUnsafe?.user?.username]); @@ -212,6 +213,7 @@ const QuestStepsList = () => { setIsEditMode, setShowSubmitView, isEditMode, + webApp }} > From 2cc846c90d44dd7ef21116060530a563f10cb00a Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Wed, 30 Aug 2023 12:29:41 +0300 Subject: [PATCH 18/31] fix media --- wondrous-bot-admin/src/utils/media/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wondrous-bot-admin/src/utils/media/index.tsx b/wondrous-bot-admin/src/utils/media/index.tsx index e26cd0ce30..14f8bdc901 100644 --- a/wondrous-bot-admin/src/utils/media/index.tsx +++ b/wondrous-bot-admin/src/utils/media/index.tsx @@ -37,7 +37,7 @@ export const uploadTelegramMedia = async ({ filename, fileType, file }) => { telegramUserId }, }); - const apiUrl = apolloResult.data.getPresignedFileUrl.url; + const apiUrl = apolloResult.data.getTelegramPresignedFileUrl.url; // TODO: parse filetype const uploadResponse = await fetch(apiUrl, { method: 'PUT', @@ -45,6 +45,7 @@ export const uploadTelegramMedia = async ({ filename, fileType, file }) => { }); // console.log('uploadResponse', uploadResponse, apiUrl) } catch (error) { + console.log(error, 'error') console.error('error', JSON.stringify(error, null, 2)); } }; From 926ca9c52bf2b07882efae344ebeeac0e685b186 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Wed, 30 Aug 2023 15:49:43 +0300 Subject: [PATCH 19/31] requirements not met stuff --- .../src/components/QuestSteps/FailReasons.tsx | 81 +++++++++++++++++++ .../src/components/QuestSteps/index.tsx | 4 +- .../src/graphql/queries/quest.ts | 7 ++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 wondrous-bot-admin/src/components/QuestSteps/FailReasons.tsx diff --git a/wondrous-bot-admin/src/components/QuestSteps/FailReasons.tsx b/wondrous-bot-admin/src/components/QuestSteps/FailReasons.tsx new file mode 100644 index 0000000000..6ca0994ed9 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/FailReasons.tsx @@ -0,0 +1,81 @@ +import { useLazyQuery } from "@apollo/client"; +import { Box, Grid, Typography } from "@mui/material"; +import PanelComponent from "components/CreateTemplate/PanelComponent"; +import { TextLabel } from "components/ViewQuest/styles"; +import { GET_QUEST_BY_ID } from "graphql/queries"; +import { useEffect, useMemo, useState } from "react"; + +const FailedReasonBody = ({ failReason }) => { + const [label, setLabel] = useState(""); + + const [getQuestById, { data }] = useLazyQuery(GET_QUEST_BY_ID, { + onCompleted: (data) => { + setLabel(`${data.getQuestById.title}`); + }, + }); + + useEffect(() => { + if (failReason.reason === "quest") { + getQuestById({ + variables: { + questId: failReason.questId, + }, + }); + } + }, [failReason, getQuestById]); + + const generateLabel = useMemo(() => { + if (failReason.reason === "level") { + return Min level: {failReason.level} + // return `Min level: ${failReason.level}`; + } + if (failReason.reason === "only_once") { + return You've made the maximum number of submissions for this quest + } + if(!label) return null; + return Complete {label} quest; + }, [failReason, label]); + + return ( + + + {generateLabel} + + + ); +}; + +const FailReasons = ({ reasons }) => { + return ( + ( + + + Woops! You can't take this quest + + + )} + renderBody={() => ( + + + Requiremenets not met + + + {reasons?.map((reason, idx) => ( + + ))} + + + )} + /> + ); +}; + +export default FailReasons; diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index 579e6aee9f..6ce1115bee 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -11,7 +11,8 @@ import { SUBMIT_QUEST } from "graphql/mutations"; import { ErrorText } from "components/Shared/styles"; import EditModal from "./EditModal"; import QuestStepComponent from "./QuestStepComponent"; -import { transformAndUploadMedia, transformAndUploadTelegramMedia } from "utils/media"; +import { transformAndUploadTelegramMedia } from "utils/media"; +import FailReasons from "./FailReasons"; const handleMediaUpload = async (mediaUploads) => Promise.all( @@ -216,6 +217,7 @@ const QuestStepsList = () => { webApp }} > + {canStartData?.userCanStartQuest?.canStart === false ? : null} {showSubmitView && !isEditMode ? ( Date: Wed, 30 Aug 2023 17:15:15 +0300 Subject: [PATCH 20/31] verify token holdings --- .../components/QuestSteps/StepModal/index.tsx | 4 + .../QuestSteps/Steps/VerifyButton.tsx | 97 ++++++++++++++++--- .../src/graphql/queries/quest.ts | 8 ++ 3 files changed, 96 insertions(+), 13 deletions(-) diff --git a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx index 785d0f31c3..78a79a7efc 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx @@ -9,6 +9,7 @@ import { useTakeQuest } from "utils/hooks"; const PromptComponent = ({ step }) => { const snapshotVoteTimes = step?.additionalData?.snapshotVoteTimes; + const tokenName = step?.additionalData?.tokenName; const content = useMemo(() => { if (step.prompt) { return step.prompt; @@ -28,6 +29,9 @@ const PromptComponent = ({ step }) => { if(step.type === TYPES.SNAPSHOT_SPACE_VOTE) { return `Please vote in this space at least ${snapshotVoteTimes} times` } + if(step.type === TYPES.VERIFY_TOKEN_HOLDING) { + return `Press to verify ${tokenName || 'token'} holdings` + } return null; }, [step.prompt, step.type, snapshotVoteTimes]); diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx index 0af5b6c65f..91fcb25359 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx @@ -9,6 +9,7 @@ import { VERIFY_LINK_CLICKED, VERIFY_SNAPSHOT_PROPOSAL_VOTE, VERIFY_SNAPSHOT_SPACE_VOTE, + VERIFY_TOKEN_HOLDING, VERIFY_YT_LIKED, VERIFY_YT_SUBSCRIPTION, } from "graphql/queries"; @@ -19,20 +20,33 @@ import { getBaseUrl, getWeb3ConnectUrl, getYoutubeChannelId } from "utils/common import { TYPES } from "utils/constants"; import { useTakeQuest } from "utils/hooks"; -const LinkComponent = ({ loading, link, onClick, label = "Click to verify", linkText = "Verify", error = null }) => { +const LinkComponent = ({ + loading, + link = "", + onClick, + label = "Click to verify", + linkText = "Verify", + error = null, +}) => { return ( {loading ? : null} - - {linkText} - + {link ? ( + + {linkText} + + ) : ( + + {linkText} + + )} {error ? {error} : null} ); @@ -354,12 +368,68 @@ const SnapshotButton = ({ step, cmtyUser, handleLinkClick, startCmtyUserPolling, ); }; +const VerifyTokenHoldingButton = ({ step, startCmtyUserPolling, stopCmtyUserPolling, cmtyUser, handleLinkClick }) => { + const { nextStep, onChange } = useTakeQuest(); + + const tokenChain = step?.additionalData?.tokenChain; + const tokenAddress = step?.additionalData?.tokenAddress; + const tokenAmount = step?.additionalData?.tokenAmount; + const tokenType = step?.additionalData?.tokenType; + const tokenDecimals = step?.additionalData?.tokenDecimals; + + const [verifyTokenHolding, { loading, data }] = useLazyQuery(VERIFY_TOKEN_HOLDING, { + notifyOnNetworkStatusChange: true, + fetchPolicy: "network-only", + onCompleted: (data) => { + if (data?.verifyTokenHolding?.userHasTokens) { + onChange({ + id: step?.id, + value: true, + }); + nextStep(); + } + }, + }); + + const onClick = async () => { + return handleLinkClick({ + action: async () => { + verifyTokenHolding({ + variables: { + telegramUserId: cmtyUser?.telegramId?.toString(), + tokenChain, + tokenAddress, + tokenAmount, + tokenType, + tokenDecimals, + }, + }); + }, + }); + }; + + const web3VerifyCallback = () => { + setTimeout(() => startCmtyUserPolling(1000), 3000); + }; + + + if (!cmtyUser?.web3Address) { + return ; + } + + return ; +}; + const COMPONENTS = { [TYPES.LINK_CLICK]: LinkClickButton, [TYPES.SUBSCRIBE_YT_CHANNEL]: YoutubeButton, [TYPES.LIKE_YT_VIDEO]: YoutubeButton, [TYPES.SNAPSHOT_PROPOSAL_VOTE]: SnapshotButton, [TYPES.SNAPSHOT_SPACE_VOTE]: SnapshotButton, + [TYPES.VERIFY_TOKEN_HOLDING]: VerifyTokenHoldingButton, }; export const VerifyButton = ({ step }) => { @@ -375,9 +445,10 @@ export const VerifyButton = ({ step }) => { await action(); } - setTimeout(() => { - callback(); - }, timeout); + callback && + setTimeout(() => { + callback?.(); + }, timeout); }; const { telegramUser } = useTakeQuest(); diff --git a/wondrous-bot-admin/src/graphql/queries/quest.ts b/wondrous-bot-admin/src/graphql/queries/quest.ts index a85ed438e4..ecade99d9a 100644 --- a/wondrous-bot-admin/src/graphql/queries/quest.ts +++ b/wondrous-bot-admin/src/graphql/queries/quest.ts @@ -314,4 +314,12 @@ export const VERIFY_SNAPSHOT_SPACE_VOTE = gql` userVotedSpace } } +`; + +export const VERIFY_TOKEN_HOLDING = gql` + query verifyTokenHolding($telegramUserId:String, $tokenChain:String, $tokenAddress:String, $tokenAmount:String, $tokenType:String, $tokenDecimals:String) { + verifyTokenHolding(telegramUserId: $telegramUserId, tokenChain: $tokenChain, tokenAddress: $tokenAddress, tokenAmount: $tokenAmount, tokenType: $tokenType, tokenDecimals: $tokenDecimals) { + userHasTokens + } + } `; \ No newline at end of file From a9259e629f27d69643b2a4b859896cb0a2ecd6b9 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Wed, 30 Aug 2023 20:58:00 +0300 Subject: [PATCH 21/31] data collection types --- .../components/AutocompleteComponent.tsx | 7 +- .../QuestSteps/QuestStepComponent.tsx | 3 +- .../QuestSteps/Steps/DataCollection.tsx | 121 +++++++++++ .../QuestSteps/Steps/OptionSelect.tsx | 1 - .../src/components/QuestSteps/index.tsx | 78 ++++--- .../src/components/Shared/styles.tsx | 4 +- .../src/components/ViewQuestResults/index.tsx | 2 +- wondrous-bot-admin/src/utils/countries.ts | 199 ++++++++++++++++++ 8 files changed, 379 insertions(+), 36 deletions(-) create mode 100644 wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx create mode 100644 wondrous-bot-admin/src/utils/countries.ts diff --git a/wondrous-bot-admin/src/components/AddFormEntity/components/AutocompleteComponent.tsx b/wondrous-bot-admin/src/components/AddFormEntity/components/AutocompleteComponent.tsx index 58c71250cc..dbfe835c5b 100644 --- a/wondrous-bot-admin/src/components/AddFormEntity/components/AutocompleteComponent.tsx +++ b/wondrous-bot-admin/src/components/AddFormEntity/components/AutocompleteComponent.tsx @@ -4,7 +4,7 @@ import CheckCircleIcon from "components/Icons/CheckCircle"; import SearchIcon from "components/Icons/Search"; import { useState } from "react"; -const AutocompleteOptionsComponent = ({ options, onChange, value }) => { +const AutocompleteOptionsComponent = ({ options, onChange, value, fullWidth = false, autocompletProps = {} }) => { const [isOpen, setIsOpen] = useState(false); const handleOpenClose = (status) => () => setIsOpen(() => status); const handleChange = (e, option) => onChange(option.value); @@ -50,7 +50,7 @@ const AutocompleteOptionsComponent = ({ options, onChange, value }) => { }} > - {option.label} + {option.label || option.value} {option.value === value && } @@ -105,7 +105,7 @@ const AutocompleteOptionsComponent = ({ options, onChange, value }) => { borderRadius: "6px", padding: "0", height: "40px", - width: "380px", + width: fullWidth ? '100%' : '380px', "& .MuiInputBase-root.MuiOutlinedInput-root": { "& .MuiOutlinedInput-notchedOutline": { border: "none", @@ -134,6 +134,7 @@ const AutocompleteOptionsComponent = ({ options, onChange, value }) => { transform: "none", }, }} + {...autocompletProps} /> ); }; diff --git a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx index 5007e5ccc3..0354554e06 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx @@ -10,6 +10,7 @@ import AttachmentType from "./Steps/Attachment"; import OptionSelect from "./Steps/OptionSelect"; import { VerifyButton } from "./Steps/VerifyButton"; import { Image } from "./styles"; +import DataCollectionComponent from "./Steps/DataCollection"; const COMPONENTS_CONFIG: any = { [TYPES.TEXT_FIELD]: StepTextField, @@ -24,7 +25,7 @@ const COMPONENTS_CONFIG: any = { [TYPES.SNAPSHOT_SPACE_VOTE]: VerifyButton, [TYPES.VERIFY_TOKEN_HOLDING]: VerifyButton, - [TYPES.DATA_COLLECTION]: () => null, + [TYPES.DATA_COLLECTION]: DataCollectionComponent }; const IMAGES_CONFIG = { diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx new file mode 100644 index 0000000000..ed149be300 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx @@ -0,0 +1,121 @@ +import { Grid, Box, Typography } from "@mui/material"; +import { StyledCheckbox } from "components/PaymentLedger/styles"; +import TextField from "components/Shared/TextField"; +import { ButtonIconWrapper, ErrorText } from "components/Shared/styles"; +import { useMemo, useState } from "react"; +import { DATA_COLLECTION_TYPES, TYPES } from "utils/constants"; + +import AddIcon from "@mui/icons-material/Add"; +import AutocompleteOptionsComponent from "components/AddFormEntity/components/AutocompleteComponent"; +import countries from "utils/countries"; + +const SelectOption = ({ step, onChange, value = []}) => { + const [inputValue, setInputValue] = useState(""); + console.log(value, 'VALUE1') + const allOptions = useMemo(() => { + const initialOptionsTexts = step.options.map((opt) => opt.text); + const addedOptions = + value + ?.filter((v) => !initialOptionsTexts.includes(v)) + .map((text, index) => ({ + text, + position: step.options.length + index, + correct: null, + __typename: "QuestStepOption", + })) || []; + return [...step.options, ...addedOptions]; + }, [step.options, value]); + + const handleCheckboxChange = (optionText) => { + if (value.includes(optionText)) { + onChange(value.filter((v) => v !== optionText)); + } else { + onChange([...value, optionText]); + } + }; + + const handleInputChange = (value) => { + setInputValue(value); + }; + + const handleAddClick = () => { + if (inputValue && !allOptions.find((opt) => opt.text === inputValue)) { + onChange([...value, inputValue]); + setInputValue(""); + } + }; + + return ( + + {allOptions.map((option, idx) => { + return ( + + handleCheckboxChange(option.text)} + /> + + {option.text} + + + ); + })} + + + + + + + + ); +}; + +const LocationType = ({ step, onChange, value }) => { + return ( + + option.value, + }} + options={countries} + value={value} + onChange={onChange} + fullWidth + /> + + ); +}; + +const DataCollectionComponent = ({ step, onChange, value }) => { + const { dataCollectionType } = step?.additionalData || {}; + + if ([DATA_COLLECTION_TYPES.INTERESTS, DATA_COLLECTION_TYPES.SKILLS].includes(dataCollectionType)) { + return ; + } + if (dataCollectionType === DATA_COLLECTION_TYPES.LOCATION) { + return ; + } + return null; +}; + +export default DataCollectionComponent; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx index 0f650088d7..591f4b247f 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx @@ -5,7 +5,6 @@ import { useMemo } from "react"; import { TYPES } from "utils/constants"; export const OptionSelect = ({ step, onChange, value, setIsActionDisabled, isActionDisabled }) => { - console.log(value, 'VALUE') const opacity = useMemo(() => { if (step.type === TYPES.SINGLE_QUIZ && value && value.length > 0) { return 0.3; diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index 6ce1115bee..82a6d4adfa 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -1,4 +1,4 @@ -import { SELECT_TYPES, TYPES } from "utils/constants"; +import { DATA_COLLECTION_TYPES, SELECT_TYPES, TYPES } from "utils/constants"; import { Grid } from "@mui/material"; import { useEffect, useState } from "react"; import { Web3Connect } from "./Steps/VerifyButton"; @@ -15,21 +15,20 @@ import { transformAndUploadTelegramMedia } from "utils/media"; import FailReasons from "./FailReasons"; const handleMediaUpload = async (mediaUploads) => -Promise.all( - mediaUploads.map(async (file) => { - try { - const { filename, fileType } = await transformAndUploadTelegramMedia({ file }); - return { - uploadSlug: filename, - type: fileType, - name: file.name, - }; - } catch (error) { - return null; - } - }) -); - + Promise.all( + mediaUploads.map(async (file) => { + try { + const { filename, fileType } = await transformAndUploadTelegramMedia({ file }); + return { + uploadSlug: filename, + type: fileType, + name: file.name, + }; + } catch (error) { + return null; + } + }) + ); const ErrorHelpers = ({ error, callback, telegramUserId }) => { const errorCode = error?.graphQLErrors?.[0]?.extensions?.errorCode; @@ -111,7 +110,7 @@ const QuestStepsList = () => { const handleSubmit = async () => { const questSubmissions = []; - + for (const step of data?.getQuestById.steps) { const answer = responses[step.id]; const isQuestSkipped = responses[step.id] === null; @@ -136,19 +135,19 @@ const QuestStepsList = () => { selectedValues: isQuestSkipped ? null : answer, }); } else if (step.type === TYPES.ATTACHMENTS) { - //TODO: fix upload media from web app , probably separate endpoint const stepsMedia = isQuestSkipped ? [null] : await handleMediaUpload(answer); - console.log(stepsMedia, 'STEPS MEDIA') questSubmissions.push({ stepId: step.id, order: step.order, skipped: isQuestSkipped, - attachments: isQuestSkipped ? null : stepsMedia.map((media) => ({ - filename: media.name, - type: media.type, - uploadSlug: media.uploadSlug - })) - }) + attachments: isQuestSkipped + ? null + : stepsMedia.map((media) => ({ + filename: media.name, + type: media.type, + uploadSlug: media.uploadSlug, + })), + }); } else if ([TYPES.LIKE_YT_VIDEO, TYPES.SUBSCRIBE_YT_CHANNEL].includes(step.type)) { questSubmissions.push({ stepId: step.id, @@ -163,6 +162,28 @@ const QuestStepsList = () => { skipped: isQuestSkipped, verified: isQuestSkipped ? false : true, }); + } else if ([TYPES.VERIFY_TOKEN_HOLDING].includes(step.type)) { + questSubmissions.push({ + stepId: step.id, + order: step.order, + skipped: isQuestSkipped, + verified: isQuestSkipped ? false : true, + }); + } else if (step.type === TYPES.DATA_COLLECTION) { + const collectionType = step.additionalData?.dataCollectionType; + let submission: any = { + stepId: step.id, + order: step.order, + skipped: isQuestSkipped, + verified: isQuestSkipped ? false : true, + dataCollectionType: collectionType, + }; + if (collectionType === DATA_COLLECTION_TYPES.LOCATION) { + submission.content = isQuestSkipped ? null : answer; + } else { + submission.selectedValues = isQuestSkipped ? null : answer; + } + questSubmissions.push(submission); } } const submissionInput = { @@ -178,7 +199,6 @@ const QuestStepsList = () => { }); if (isEditMode) setIsEditMode(false); } catch (error) {} - //TODO: handle reward && next screen }; const steps = data?.getQuestById?.steps || []; @@ -214,10 +234,12 @@ const QuestStepsList = () => { setIsEditMode, setShowSubmitView, isEditMode, - webApp + webApp, }} > - {canStartData?.userCanStartQuest?.canStart === false ? : null} + {canStartData?.userCanStartQuest?.canStart === false ? ( + + ) : null} {showSubmitView && !isEditMode ? ( height}; - width: 30px; + width: ${({ width = "30px" }) => width}; &:hover { opacity: 0.8; } diff --git a/wondrous-bot-admin/src/components/ViewQuestResults/index.tsx b/wondrous-bot-admin/src/components/ViewQuestResults/index.tsx index 813e290014..5e63b469be 100644 --- a/wondrous-bot-admin/src/components/ViewQuestResults/index.tsx +++ b/wondrous-bot-admin/src/components/ViewQuestResults/index.tsx @@ -153,7 +153,7 @@ const ViewQuestResults = ({ quest, rewards }) => { const submissions = submissionsData?.getQuestSubmissions?.map((submission) => ({ - user: submission?.creator?.username || submission?.creator?.discordUsername, + user: submission?.creator?.username || submission?.creator?.discordUsername || submission?.creator?.telegramUsername, pointReward: quest?.pointReward, stepsData: submission?.stepsData, steps: quest?.steps, diff --git a/wondrous-bot-admin/src/utils/countries.ts b/wondrous-bot-admin/src/utils/countries.ts new file mode 100644 index 0000000000..efcfc65203 --- /dev/null +++ b/wondrous-bot-admin/src/utils/countries.ts @@ -0,0 +1,199 @@ +const countries = [ + { value: "Afghanistan", code: "AF" }, + { value: "Albania", code: "AL" }, + { value: "Algeria", code: "DZ" }, + { value: "Andorra", code: "AD" }, + { value: "Angola", code: "AO" }, + { value: "Antigua and Barbuda", code: "AG" }, + { value: "Argentina", code: "AR" }, + { value: "Armenia", code: "AM" }, + { value: "Australia", code: "AU" }, + { value: "Austria", code: "AT" }, + { value: "Azerbaijan", code: "AZ" }, + { value: "Bahamas", code: "BS" }, + { value: "Bahrain", code: "BH" }, + { value: "Bangladesh", code: "BD" }, + { value: "Barbados", code: "BB" }, + { value: "Belarus", code: "BY" }, + { value: "Belgium", code: "BE" }, + { value: "Belize", code: "BZ" }, + { value: "Benin", code: "BJ" }, + { value: "Bhutan", code: "BT" }, + { value: "Bolivia", code: "BO" }, + { value: "Bosnia and Herzegovina", code: "BA" }, + { value: "Botswana", code: "BW" }, + { value: "Brazil", code: "BR" }, + { value: "Brunei", code: "BN" }, + { value: "Bulgaria", code: "BG" }, + { value: "Burkina Faso", code: "BF" }, + { value: "Burundi", code: "BI" }, + { value: "Côte d'Ivoire", code: "CI" }, + { value: "Cabo Verde", code: "CV" }, + { value: "Cambodia", code: "KH" }, + { value: "Cameroon", code: "CM" }, + { value: "Canada", code: "CA" }, + { value: "Central African Republic", code: "CF" }, + { value: "Chad", code: "TD" }, + { value: "Chile", code: "CL" }, + { value: "China", code: "CN" }, + { value: "Colombia", code: "CO" }, + { value: "Comoros", code: "KM" }, + { value: "Congo (Congo-Brazzaville)", code: "CG" }, + { value: "Costa Rica", code: "CR" }, + { value: "Croatia", code: "HR" }, + { value: "Cuba", code: "CU" }, + { value: "Cyprus", code: "CY" }, + { value: "Czechia (Czech Republic)", code: "CZ" }, + { value: "Democratic Republic of the Congo", code: "CD" }, + { value: "Denmark", code: "DK" }, + { value: "Djibouti", code: "DJ" }, + { value: "Dominica", code: "DM" }, + { value: "Dominican Republic", code: "DO" }, + { value: "Ecuador", code: "EC" }, + { value: "Egypt", code: "EG" }, + { value: "El Salvador", code: "SV" }, + { value: "Equatorial Guinea", code: "GQ" }, + { value: "Eritrea", code: "ER" }, + { value: "Estonia", code: "EE" }, + { value: "Eswatini (fmr. Swaziland)", code: "SZ" }, + { value: "Ethiopia", code: "ET" }, + { value: "Fiji", code: "FJ" }, + { value: "Finland", code: "FI" }, + { value: "France", code: "FR" }, + { value: "Gabon", code: "GA" }, + { value: "Gambia", code: "GM" }, + { value: "Georgia", code: "GE" }, + { value: "Germany", code: "DE" }, + { value: "Ghana", code: "GH" }, + { value: "Greece", code: "GR" }, + { value: "Grenada", code: "GD" }, + { value: "Guatemala", code: "GT" }, + { value: "Guinea", code: "GN" }, + { value: "Guinea-Bissau", code: "GW" }, + { value: "Guyana", code: "GY" }, + { value: "Haiti", code: "HT" }, + { value: "Holy See", code: "VA" }, + { value: "Honduras", code: "HN" }, + { value: "Hungary", code: "HU" }, + { value: "Iceland", code: "IS" }, + { value: "India", code: "IN" }, + { value: "Indonesia", code: "ID" }, + { value: "Iran", code: "IR" }, + { value: "Iraq", code: "IQ" }, + { value: "Ireland", code: "IE" }, + { value: "Israel", code: "IL" }, + { value: "Italy", code: "IT" }, + { value: "Jamaica", code: "JM" }, + { value: "Japan", code: "JP" }, + { value: "Jordan", code: "JO" }, + { value: "Kazakhstan", code: "KZ" }, + { value: "Kenya", code: "KE" }, + { value: "Kiribati", code: "KI" }, + { value: "Kuwait", code: "KW" }, + { value: "Kyrgyzstan", code: "KG" }, + { value: "Laos", code: "LA" }, + { value: "Latvia", code: "LV" }, + { value: "Lebanon", code: "LB" }, + { value: "Lesotho", code: "LS" }, + { value: "Liberia", code: "LR" }, + { value: "Libya", code: "LY" }, + { value: "Liechtenstein", code: "LI" }, + { value: "Lithuania", code: "LT" }, + { value: "Luxembourg", code: "LU" }, + { value: "Madagascar", code: "MG" }, + { value: "Malawi", code: "MW" }, + { value: "Malaysia", code: "MY" }, + { value: "Maldives", code: "MV" }, + { value: "Mali", code: "ML" }, + { value: "Malta", code: "MT" }, + { value: "Marshall Islands", code: "MH" }, + { value: "Mauritania", code: "MR" }, + { value: "Mauritius", code: "MU" }, + { value: "Mexico", code: "MX" }, + { value: "Micronesia", code: "FM" }, + { value: "Moldova", code: "MD" }, + { value: "Monaco", code: "MC" }, + { value: "Mongolia", code: "MN" }, + { value: "Montenegro", code: "ME" }, + { value: "Morocco", code: "MA" }, + { value: "Mozambique", code: "MZ" }, + { value: "Myanmar (formerly Burma)", code: "MM" }, + { value: "Namibia", code: "NA" }, + { value: "Nauru", code: "NR" }, + { value: "Nepal", code: "NP" }, + { value: "Netherlands", code: "NL" }, + { value: "New Zealand", code: "NZ" }, + { value: "Nicaragua", code: "NI" }, + { value: "Niger", code: "NE" }, + { value: "Nigeria", code: "NG" }, + { value: "North Korea", code: "KP" }, + { value: "North Macedonia (formerly Macedonia)", code: "MK" }, + { value: "Norway", code: "NO" }, + { value: "Oman", code: "OM" }, + { value: "Pakistan", code: "PK" }, + { value: "Palau", code: "PW" }, + { value: "Palestine State", code: "PS" }, + { value: "Panama", code: "PA" }, + { value: "Papua New Guinea", code: "PG" }, + { value: "Paraguay", code: "PY" }, + { value: "Peru", code: "PE" }, + { value: "Philippines", code: "PH" }, + { value: "Poland", code: "PL" }, + { value: "Portugal", code: "PT" }, + { value: "Qatar", code: "QA" }, + { value: "Romania", code: "RO" }, + { value: "Russia", code: "RU" }, + { value: "Rwanda", code: "RW" }, + { value: "Saint Kitts and Nevis", code: "KN" }, + { value: "Saint Lucia", code: "LC" }, + { value: "Saint Vincent and the Grenadines", code: "VC" }, + { value: "Samoa", code: "WS" }, + { value: "San Marino", code: "SM" }, + { value: "Sao Tome and Principe", code: "ST" }, + { value: "Saudi Arabia", code: "SA" }, + { value: "Senegal", code: "SN" }, + { value: "Serbia", code: "RS" }, + { value: "Seychelles", code: "SC" }, + { value: "Sierra Leone", code: "SL" }, + { value: "Singapore", code: "SG" }, + { value: "Slovakia", code: "SK" }, + { value: "Slovenia", code: "SI" }, + { value: "Solomon Islands", code: "SB" }, + { value: "Somalia", code: "SO" }, + { value: "South Africa", code: "ZA" }, + { value: "South Korea", code: "KR" }, + { value: "South Sudan", code: "SS" }, + { value: "Spain", code: "ES" }, + { value: "Sri Lanka", code: "LK" }, + { value: "Sudan", code: "SD" }, + { value: "Surivalue", code: "SR" }, + { value: "Sweden", code: "SE" }, + { value: "Switzerland", code: "CH" }, + { value: "Syria", code: "SY" }, + { value: "Tajikistan", code: "TJ" }, + { value: "Tanzania", code: "TZ" }, + { value: "Thailand", code: "TH" }, + { value: "Timor-Leste", code: "TL" }, + { value: "Togo", code: "TG" }, + { value: "Tonga", code: "TO" }, + { value: "Trinidad and Tobago", code: "TT" }, + { value: "Tunisia", code: "TN" }, + { value: "Turkey", code: "TR" }, + { value: "Turkmenistan", code: "TM" }, + { value: "Tuvalu", code: "TV" }, + { value: "Uganda", code: "UG" }, + { value: "Ukraine", code: "UA" }, + { value: "United Arab Emirates", code: "AE" }, + { value: "United Kingdom", code: "GB" }, + { value: "United States of America", code: "US" }, + { value: "Uruguay", code: "UY" }, + { value: "Uzbekistan", code: "UZ" }, + { value: "Vanuatu", code: "VU" }, + { value: "Venezuela", code: "VE" }, + { value: "Vietnam", code: "VN" }, + { value: "Yemen", code: "YE" }, + { value: "Zambia", code: "ZM" }, + { value: "Zimbabwe", code: "ZW" }, +]; + +export default countries; From 23ba82caf54595565aadabaf1b670145f9801151 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Wed, 30 Aug 2023 22:08:30 +0300 Subject: [PATCH 22/31] bot name --- wondrous-bot-admin/src/utils/discord/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wondrous-bot-admin/src/utils/discord/index.tsx b/wondrous-bot-admin/src/utils/discord/index.tsx index 0bda549098..b3b41656f6 100644 --- a/wondrous-bot-admin/src/utils/discord/index.tsx +++ b/wondrous-bot-admin/src/utils/discord/index.tsx @@ -84,13 +84,13 @@ export const getDiscordUrl = (callbackUrl = '/discord/callback', params = '') => export const getTelegramBotLink = () => { - let botName = 'wonder_communities_bot' + let botName = 'wonderverse_bot' let link = `https://t.me/${botName}?startgroup=true&admin=post_messages`; if (import.meta.env.VITE_PRODUCTION) { return link; } if(import.meta.env.VITE_STAGING) { - botName = 'communities_staging_bot' + botName = 'wonderverse_staging_bot' return link; } return "https://t.me/communities_test_bot?startgroup=true&admin=post_messages"; From 72f6a71c7cf3255a83f17eaee79c5210e39702a9 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Fri, 1 Sep 2023 11:47:02 +0300 Subject: [PATCH 23/31] bugfixes --- .../components/AutocompleteComponent.tsx | 3 +- .../QuestSteps/QuestStepComponent.tsx | 15 ++-- .../components/QuestSteps/StepModal/index.tsx | 4 +- .../QuestSteps/Steps/DataCollection.tsx | 6 +- .../QuestSteps/Steps/OptionSelect.tsx | 68 +++++++++---------- .../src/components/QuestSteps/Steps/Text.tsx | 9 ++- .../src/components/QuestSteps/index.tsx | 56 ++++++++++++++- .../src/pages/telegram/start-quest/index.tsx | 1 - 8 files changed, 112 insertions(+), 50 deletions(-) diff --git a/wondrous-bot-admin/src/components/AddFormEntity/components/AutocompleteComponent.tsx b/wondrous-bot-admin/src/components/AddFormEntity/components/AutocompleteComponent.tsx index dbfe835c5b..b6491f4d94 100644 --- a/wondrous-bot-admin/src/components/AddFormEntity/components/AutocompleteComponent.tsx +++ b/wondrous-bot-admin/src/components/AddFormEntity/components/AutocompleteComponent.tsx @@ -4,7 +4,7 @@ import CheckCircleIcon from "components/Icons/CheckCircle"; import SearchIcon from "components/Icons/Search"; import { useState } from "react"; -const AutocompleteOptionsComponent = ({ options, onChange, value, fullWidth = false, autocompletProps = {} }) => { +const AutocompleteOptionsComponent = ({ options, onChange, value, fullWidth = false, autocompletProps = {}, inputProps = {} }) => { const [isOpen, setIsOpen] = useState(false); const handleOpenClose = (status) => () => setIsOpen(() => status); const handleChange = (e, option) => onChange(option.value); @@ -31,6 +31,7 @@ const AutocompleteOptionsComponent = ({ options, onChange, value, fullWidth = fa fontWeight: "500", }, }} + {...inputProps} /> )} renderOption={(props, option) => { diff --git a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx index 0354554e06..d276b3da49 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx @@ -16,7 +16,7 @@ const COMPONENTS_CONFIG: any = { [TYPES.TEXT_FIELD]: StepTextField, [TYPES.MULTI_QUIZ]: OptionSelect, [TYPES.SINGLE_QUIZ]: OptionSelect, - [TYPES.NUMBER]: (props) => , + [TYPES.NUMBER]: (props) => , [TYPES.ATTACHMENTS]: AttachmentType, [TYPES.LINK_CLICK]: VerifyButton, [TYPES.SUBSCRIBE_YT_CHANNEL]: VerifyButton, @@ -36,7 +36,7 @@ const IMAGES_CONFIG = { const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = false }) => { const Component: React.FC = COMPONENTS_CONFIG[step?.type]; - const [isActionDisabled, setIsActionDisabled] = useState(false); + const [customHandlers, setCustomHandlers] = useState(null); const { onChange, isEditMode } = useTakeQuest(); if (!isActive || !step) return null; if (Component) { @@ -76,13 +76,13 @@ const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = fal ) } renderBody={() => ( - + {IMAGES_CONFIG[step.type] ? : null} onChange({ id: step.id, value })} placeholder="Enter answer" /> @@ -93,7 +93,10 @@ const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = fal { ); }; -export const StepModal = ({ children, step, disabled, nextStepId }) => { +export const StepModal = ({ children, step, disabled, customHandlers }) => { const { nextStep, isEditMode } = useTakeQuest(); + + return ( diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx index ed149be300..afba2c6547 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx @@ -9,9 +9,8 @@ import AddIcon from "@mui/icons-material/Add"; import AutocompleteOptionsComponent from "components/AddFormEntity/components/AutocompleteComponent"; import countries from "utils/countries"; -const SelectOption = ({ step, onChange, value = []}) => { +const SelectOption = ({ step, onChange, value = [] }) => { const [inputValue, setInputValue] = useState(""); - console.log(value, 'VALUE1') const allOptions = useMemo(() => { const initialOptionsTexts = step.options.map((opt) => opt.text); const addedOptions = @@ -97,6 +96,9 @@ const LocationType = ({ step, onChange, value }) => { autocompletProps={{ getOptionLabel: (option) => option.value, }} + inputProps={{ + sx: {}, + }} options={countries} value={value} onChange={onChange} diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx index 591f4b247f..e98e8cbe0a 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx @@ -1,60 +1,55 @@ import { Box, Grid, Typography } from "@mui/material"; import { StyledCheckbox } from "components/PaymentLedger/styles"; import { ErrorText } from "components/Shared/styles"; -import { useMemo } from "react"; +import { useMemo, useState } from "react"; import { TYPES } from "utils/constants"; +import { useTakeQuest } from "utils/hooks"; -export const OptionSelect = ({ step, onChange, value, setIsActionDisabled, isActionDisabled }) => { - const opacity = useMemo(() => { - if (step.type === TYPES.SINGLE_QUIZ && value && value.length > 0) { - return 0.3; - } - return 1; - }, [value, step.type]); +export const OptionSelect = ({ step, onChange, value }) => { + + const {errors} = useTakeQuest(); + const opacity = step.type === TYPES.SINGLE_QUIZ && value && value.length > 0 ? 0.3 : 1; + const correctValues = step?.options?.filter((option) => option.correct).map((option) => option.text); const allCorrect = useMemo(() => { if (correctValues && correctValues.length > 0) { - if (step?.type === TYPES.SINGLE_QUIZ) { - return correctValues.includes(value?.[0]); - } else { + if (step?.type === TYPES.MULTI_QUIZ) { return ( - correctValues.every((correctValue) => value?.includes(correctValue)) && value?.length === correctValues.length + correctValues.every((correctValue) => value?.includes(correctValue)) && + value?.length === correctValues.length ); } - } else { - return null; + return step?.type === TYPES.SINGLE_QUIZ ? correctValues.includes(value?.[0]) : null; } + return step?.type === TYPES.MULTI_QUIZ ? value?.length > 0 : null; }, [correctValues, value, step.type]); + - const isCorrect = useMemo(() => { - if (correctValues && correctValues.length > 0) { - if (!allCorrect && !isActionDisabled) { - setIsActionDisabled(true); - } - if (allCorrect && isActionDisabled) { - setIsActionDisabled(false); - } - return allCorrect; - } else return null; - }, [correctValues, value, allCorrect]); + const isCorrect = correctValues && correctValues.length > 0 ? allCorrect : null; const handleCheckboxChange = (e, text) => { - if (step.type === TYPES.SINGLE_QUIZ && value?.includes(text)) { - return onChange([]); + let updatedValuesSet = new Set(value || []); + + if (e.target.checked) { + updatedValuesSet.add(text); + } else { + updatedValuesSet.delete(text); } + const updatedValuesArray = [...updatedValuesSet]; + if (step.type === TYPES.SINGLE_QUIZ) { - return onChange(e.target.checked ? [text] : []); + return onChange(e.target.checked ? [text] : []); } - let defaultValues = value || []; - const values = e.target.checked ? [...defaultValues, text] : defaultValues?.filter((i) => i !== text); - return onChange(values); - }; + return onChange(updatedValuesArray); +}; const sortedOptions = useMemo(() => step?.options?.sort((a, b) => a.position - b.position), [step?.options]); + + return ( {sortedOptions.map((option, idx) => { @@ -78,19 +73,20 @@ export const OptionSelect = ({ step, onChange, value, setIsActionDisabled, isAct bgcolor={"#2A8D5C"} height="22px" width="22px" - checked={value?.includes(option.text)} + defaultChecked={value?.includes(option.text)} disabled={step.type === TYPES.SINGLE_QUIZ && value?.length > 0 && !value.includes(option.text)} onChange={(e) => handleCheckboxChange(e, option.text)} - /> + /> {option.text} ); })} - {isCorrect !== null && + {errors[step.id] ? {errors[step.id]} : null} + {/* {isCorrect !== null && !!value?.length && - (isCorrect ? null : Please select only the correct options)} + (isCorrect ? null : Please select only the correct options)} */} ); }; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx index 8864ef7bba..828e6a78fb 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx @@ -6,7 +6,14 @@ export const StepTextField = ({ step, onChange, value, placeholder = "", type = return ( <> - + ); diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index 82a6d4adfa..372819c4dc 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -61,6 +61,7 @@ const QuestStepsList = () => { const [responses, setResponses] = useState({}); const [showSubmitView, setShowSubmitView] = useState(false); const [isEditMode, setIsEditMode] = useState(false); + const [errors, setErrors] = useState({}); const webApp = (window as any)?.Telegram?.WebApp; const [getQuestById, { data, loading, refetch }] = useLazyQuery(GET_QUEST_BY_ID, { @@ -108,11 +109,51 @@ const QuestStepsList = () => { [id]: skip ? null : value, }); + const validate = (step, value) => { + const { type, id, options } = step; + + if (!SELECT_TYPES.includes(type)) return true; + setErrors({}) + + const correctValues = options?.filter((option) => option.correct).map((option) => option.text) || []; + + const isMultiQuizValid = () => { + const hasAllValuesCorrect = + correctValues.every((correctValue) => value?.includes(correctValue)) && + value.every((selectedValue) => correctValues.includes(selectedValue)); + + if (!hasAllValuesCorrect) { + setErrors(prevErrors => ({ ...prevErrors, [id]: "Please select only the correct options" })); + } + return hasAllValuesCorrect; + }; + + const isSingleQuizValid = () => { + const isCorrect = correctValues.includes(value?.[0]); + if (!isCorrect) { + setErrors(prevErrors => ({ ...prevErrors, [id]: "Please select only the correct options" })); + } + return isCorrect; + }; + + if (type === TYPES.MULTI_QUIZ && correctValues?.length > 0) { + return isMultiQuizValid(); + } + + if (type === TYPES.SINGLE_QUIZ && correctValues?.length > 0) { + return isSingleQuizValid(); + } + + return true; + }; + const handleSubmit = async () => { const questSubmissions = []; - + for (const step of data?.getQuestById.steps) { const answer = responses[step.id]; + const isValid = validate(step, answer); + if(!isValid) return; const isQuestSkipped = responses[step.id] === null; if (step.type === TYPES.TEXT_FIELD) { questSubmissions.push({ @@ -203,24 +244,33 @@ const QuestStepsList = () => { const steps = data?.getQuestById?.steps || []; + const nextStep = () => { const currentStepIdx = steps?.findIndex((step) => step.id === activeStepId); + const currentStep = steps[currentStepIdx]; const nextStepId = steps[currentStepIdx + 1]?.id; if (isEditMode) { setIsEditMode(false); return setShowSubmitView(true); } + + if (!validate(currentStep, responses[currentStep.id])) { + return; + } + if (!nextStepId) { return setShowSubmitView(true); } - setActiveStepId(steps[currentStepIdx + 1]?.id); + + setActiveStepId(nextStepId); }; const prevStep = () => { const currentStepIdx = steps?.findIndex((step) => step.id === activeStepId); setActiveStepId(steps[currentStepIdx - 1]?.id); }; + return ( { setShowSubmitView, isEditMode, webApp, + validate, + errors, }} > {canStartData?.userCanStartQuest?.canStart === false ? ( diff --git a/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx b/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx index cc9788f83b..1f3df0cc26 100644 --- a/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx +++ b/wondrous-bot-admin/src/pages/telegram/start-quest/index.tsx @@ -9,7 +9,6 @@ export const TelegramStartQuest = () => { direction: "column", justifyContent: "center", alignItems: "center", - minHeight: "100vh", padding: { xs: "14px 14px 120px 14px", sm: "24px 56px 150px 24px", From 645d13ad33f320f3050baf765ec95fd689199987 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Fri, 1 Sep 2023 11:59:37 +0300 Subject: [PATCH 24/31] fix bugs --- .../QuestSteps/Steps/OptionSelect.tsx | 37 ++++--------------- .../src/components/QuestSteps/index.tsx | 10 +++-- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx index e98e8cbe0a..8952b69d6c 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/OptionSelect.tsx @@ -11,37 +11,19 @@ export const OptionSelect = ({ step, onChange, value }) => { const opacity = step.type === TYPES.SINGLE_QUIZ && value && value.length > 0 ? 0.3 : 1; - const correctValues = step?.options?.filter((option) => option.correct).map((option) => option.text); - - const allCorrect = useMemo(() => { - if (correctValues && correctValues.length > 0) { - if (step?.type === TYPES.MULTI_QUIZ) { - return ( - correctValues.every((correctValue) => value?.includes(correctValue)) && - value?.length === correctValues.length - ); - } - return step?.type === TYPES.SINGLE_QUIZ ? correctValues.includes(value?.[0]) : null; - } - return step?.type === TYPES.MULTI_QUIZ ? value?.length > 0 : null; - }, [correctValues, value, step.type]); - - - const isCorrect = correctValues && correctValues.length > 0 ? allCorrect : null; - - const handleCheckboxChange = (e, text) => { + const handleCheckboxChange = (e, position) => { let updatedValuesSet = new Set(value || []); if (e.target.checked) { - updatedValuesSet.add(text); + updatedValuesSet.add(position); } else { - updatedValuesSet.delete(text); + updatedValuesSet.delete(position); } const updatedValuesArray = [...updatedValuesSet]; if (step.type === TYPES.SINGLE_QUIZ) { - return onChange(e.target.checked ? [text] : []); + return onChange(e.target.checked ? [position] : []); } return onChange(updatedValuesArray); @@ -64,7 +46,7 @@ export const OptionSelect = ({ step, onChange, value }) => { gap="12px" sx={{ opacity: - (step.type === TYPES.SINGLE_QUIZ && value?.includes(option.text)) || step.type !== TYPES.SINGLE_QUIZ + (step.type === TYPES.SINGLE_QUIZ && value?.includes(option.position)) || step.type !== TYPES.SINGLE_QUIZ ? 1 : opacity, }} @@ -73,9 +55,9 @@ export const OptionSelect = ({ step, onChange, value }) => { bgcolor={"#2A8D5C"} height="22px" width="22px" - defaultChecked={value?.includes(option.text)} - disabled={step.type === TYPES.SINGLE_QUIZ && value?.length > 0 && !value.includes(option.text)} - onChange={(e) => handleCheckboxChange(e, option.text)} + defaultChecked={value?.includes(option.position)} + disabled={step.type === TYPES.SINGLE_QUIZ && value?.length > 0 && !value.includes(option.position)} + onChange={(e) => handleCheckboxChange(e, option.position)} /> {option.text} @@ -84,9 +66,6 @@ export const OptionSelect = ({ step, onChange, value }) => { ); })} {errors[step.id] ? {errors[step.id]} : null} - {/* {isCorrect !== null && - !!value?.length && - (isCorrect ? null : Please select only the correct options)} */} ); }; diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index 372819c4dc..2e02d14ee0 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -114,9 +114,10 @@ const QuestStepsList = () => { if (!SELECT_TYPES.includes(type)) return true; setErrors({}) - - const correctValues = options?.filter((option) => option.correct).map((option) => option.text) || []; - + + const correctValues = options?.filter((option) => option.correct).map((option) => option.position) || []; + + const isMultiQuizValid = () => { const hasAllValuesCorrect = correctValues.every((correctValue) => value?.includes(correctValue)) && @@ -169,11 +170,12 @@ const QuestStepsList = () => { order: step.order, }); } else if (SELECT_TYPES.includes(step.type)) { + const selectedValues = step.options.filter(option => answer.includes(option.position))?.map(value => value.text) questSubmissions.push({ stepId: step.id, order: step.order, skipped: isQuestSkipped, - selectedValues: isQuestSkipped ? null : answer, + selectedValues: isQuestSkipped ? null : selectedValues, }); } else if (step.type === TYPES.ATTACHMENTS) { const stepsMedia = isQuestSkipped ? [null] : await handleMediaUpload(answer); From 2a0a054d45d11e1130481747c49fd9ac202fdfad Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Fri, 1 Sep 2023 12:18:29 +0300 Subject: [PATCH 25/31] fix num --- .../src/components/QuestSteps/Steps/Text.tsx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx index 828e6a78fb..76de1286d7 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx @@ -1,15 +1,32 @@ import { Grid } from "@mui/material"; -import { Label } from "components/AddFormEntity/components/styles"; import TextField from "components/Shared/TextField"; +const validateTypes = (type, value) => { + if (type === "number" || type === "tel") { + const re = /^[0-9\b]+$/; + if (value === "" || re.test(value)) { + return true; + } + return false; + } + return true; +}; + export const StepTextField = ({ step, onChange, value, placeholder = "", type = "text" }) => { + const handleInputChange = (value) => { + const isValid = validateTypes(type, value); + if (isValid) { + return onChange(value); + } + }; + return ( <> Date: Fri, 1 Sep 2023 12:28:11 +0300 Subject: [PATCH 26/31] moved attaches above step input --- .../QuestSteps/QuestStepComponent.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx index d276b3da49..153dbdde45 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx @@ -80,17 +80,11 @@ const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = fal customHandlers={customHandlers} > {IMAGES_CONFIG[step.type] ? : null} - onChange({ id: step.id, value })} - placeholder="Enter answer" - /> {step?.media ? ( - + {step?.media?.map((item) => { return ( - + ) : null} + onChange({ id: step.id, value })} + placeholder="Enter answer" + /> + )} /> From 5c2d1ec936b3dbd01199ec7f65255799cb9767d2 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Fri, 1 Sep 2023 14:01:10 +0300 Subject: [PATCH 27/31] twitter wip --- .../QuestSteps/QuestStepComponent.tsx | 8 +- .../QuestSteps/Steps/LinkComponent.tsx | 36 ++++++++ .../Steps/TwitterComponents/index.tsx | 84 +++++++++++++++++++ .../QuestSteps/Steps/VerifyButton.tsx | 38 ++------- .../src/graphql/mutations/user.ts | 4 +- .../src/graphql/queries/index.ts | 1 + .../src/graphql/queries/questSubmission.ts | 35 ++++++++ .../src/pages/twitter/callback/index.tsx | 5 +- wondrous-bot-admin/src/utils/common.tsx | 20 +++++ 9 files changed, 194 insertions(+), 37 deletions(-) create mode 100644 wondrous-bot-admin/src/components/QuestSteps/Steps/LinkComponent.tsx create mode 100644 wondrous-bot-admin/src/components/QuestSteps/Steps/TwitterComponents/index.tsx create mode 100644 wondrous-bot-admin/src/graphql/queries/questSubmission.ts diff --git a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx index 153dbdde45..69d7ad00cb 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx @@ -23,9 +23,13 @@ const COMPONENTS_CONFIG: any = { [TYPES.LIKE_YT_VIDEO]: VerifyButton, [TYPES.SNAPSHOT_PROPOSAL_VOTE]: VerifyButton, [TYPES.SNAPSHOT_SPACE_VOTE]: VerifyButton, - [TYPES.VERIFY_TOKEN_HOLDING]: VerifyButton, - [TYPES.DATA_COLLECTION]: DataCollectionComponent + [TYPES.DATA_COLLECTION]: DataCollectionComponent, + [TYPES.LIKE_TWEET]: VerifyButton, + [TYPES.FOLLOW_TWITTER]: VerifyButton, + [TYPES.REPLY_TWEET]: VerifyButton, + [TYPES.REPLY_TWEET]: VerifyButton, + [TYPES.TWEET_WITH_PHRASE]: VerifyButton }; const IMAGES_CONFIG = { diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/LinkComponent.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/LinkComponent.tsx new file mode 100644 index 0000000000..de671f9aa7 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/LinkComponent.tsx @@ -0,0 +1,36 @@ +import { Box } from "@mui/material"; +import { Label } from "components/AddFormEntity/components/styles"; +import Spinner from "components/Shared/Spinner"; +import { ErrorText, SharedSecondaryButton } from "components/Shared/styles"; + +export const LinkComponent = ({ + loading, + link = "", + onClick, + label = "Click to verify", + linkText = "Verify", + error = null, +}) => { + return ( + + {loading ? : null} + + {link ? ( + + {linkText} + + ) : ( + + {linkText} + + )} + {error ? {error} : null} + + ); +}; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/TwitterComponents/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/TwitterComponents/index.tsx new file mode 100644 index 0000000000..945ca266a6 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/TwitterComponents/index.tsx @@ -0,0 +1,84 @@ +// step={step} +// startCmtyUserPolling={startPolling} +// stopCmtyUserPolling={stopPolling} +// cmtyUser={data?.getIntegrationCmtyUser} +// handleLinkClick={handleLinkClick} + +import { useLazyQuery } from "@apollo/client"; +import { SharedSecondaryButton } from "components/Shared/styles"; +import { VERIFY_TWEET_LIKED } from "graphql/queries"; +import { useMemo } from "react"; +import { buildTwitterAuthUrl } from "utils/common"; +import { LinkComponent } from "../LinkComponent"; +import { useTakeQuest } from "utils/hooks"; + +const TwitterOauth = ({ telegramUserId, callback }) => { + const state = `telegramUserId=${telegramUserId}`; + const link = buildTwitterAuthUrl(state); + + const handleClick = () => { + return callback?.(); + }; + + return ( + + Connect Twitter + + ); +}; + +export const VerifyLikeTweet = ({ step, startCmtyUserPolling, stopCmtyUserPolling, cmtyUser, handleLinkClick }) => { + const tweetLink = step?.additionalData?.tweetLink; + + const { nextStep, onChange } = useTakeQuest(); + + const [verifyLikeTweet, { data, error, loading }] = useLazyQuery(VERIFY_TWEET_LIKED); + + const tweetId = tweetLink.split("/").pop(); + const cleanedTweetId = tweetId?.split("?")[0]; + + const handleCallback = () => setTimeout(() => startCmtyUserPolling(1000), 3000); + + const reconnectTwitterErrors = ["twitter_token_expired", "twitter_missing_scope", "twitter_not_connected"]; + const errorCode: any = error?.graphQLErrors[0]?.extensions.errorCode; + + if (!cmtyUser?.twitterInfo || reconnectTwitterErrors.includes(errorCode)) { + return ; + } + + const handleClick = async () => { + const { data, error } = await verifyLikeTweet({ + variables: { + cmtyUserId: cmtyUser?.id, + tweetId: cleanedTweetId, + }, + }); + if (data?.verifyTweetLiked?.userLikedTweet) { + onChange({ + id: step?.id, + value: true, + }); + return nextStep(); + } + }; + const errorMessage = useMemo(() => { + if (error?.graphQLErrors && error?.graphQLErrors[0]?.extensions.errorCode === "twitter_not_connected") { + return "Twitter not connected, please connect your twitter account and try again"; + } + if (error?.graphQLErrors && error?.graphQLErrors[0]?.extensions.errorCode === "twitter_missing_scope") { + return "Proposal was not voted on, try again"; + } + if (error) { + return "Something went wrong. Please try again or contact support"; + } + return null; + }, [data, error]); + + return ; +}; + +export const VerifyFollowAccount = () => null; + +export const VerifyReplyToTweet = () => null; + +export const VerifyRetweet = () => null; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx index 91fcb25359..ca24897d68 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx @@ -19,38 +19,8 @@ import { getYouTubeVideoId } from "services/validators/customValidation"; import { getBaseUrl, getWeb3ConnectUrl, getYoutubeChannelId } from "utils/common"; import { TYPES } from "utils/constants"; import { useTakeQuest } from "utils/hooks"; - -const LinkComponent = ({ - loading, - link = "", - onClick, - label = "Click to verify", - linkText = "Verify", - error = null, -}) => { - return ( - - {loading ? : null} - - {link ? ( - - {linkText} - - ) : ( - - {linkText} - - )} - {error ? {error} : null} - - ); -}; +import { VerifyFollowAccount, VerifyLikeTweet, VerifyReplyToTweet, VerifyRetweet } from "./TwitterComponents"; +import { LinkComponent } from "./LinkComponent"; const GoogleVerify = ({ telegramUserId, callback }) => { const handleClick = () => { @@ -430,6 +400,10 @@ const COMPONENTS = { [TYPES.SNAPSHOT_PROPOSAL_VOTE]: SnapshotButton, [TYPES.SNAPSHOT_SPACE_VOTE]: SnapshotButton, [TYPES.VERIFY_TOKEN_HOLDING]: VerifyTokenHoldingButton, + [TYPES.LIKE_TWEET]: VerifyLikeTweet, + [TYPES.FOLLOW_TWITTER]: VerifyFollowAccount, + [TYPES.REPLY_TWEET]: VerifyReplyToTweet, + [TYPES.RETWEET]: VerifyRetweet, }; export const VerifyButton = ({ step }) => { diff --git a/wondrous-bot-admin/src/graphql/mutations/user.ts b/wondrous-bot-admin/src/graphql/mutations/user.ts index f09e3f6844..d11543c142 100644 --- a/wondrous-bot-admin/src/graphql/mutations/user.ts +++ b/wondrous-bot-admin/src/graphql/mutations/user.ts @@ -146,8 +146,8 @@ export const CLOSE_MAIN_BANNER = gql` `; export const VERIFY_COMMUNITY_USER_TWITTER = gql` - mutation verifyCommunityUserTwitter($code: String, $discordId: String) { - verifyCommunityUserTwitter(code: $code, discordId: $discordId) { + mutation verifyCommunityUserTwitter($code: String, $discordId: String, $telegramUserId: String) { + verifyCommunityUserTwitter(code: $code, discordId: $discordId, telegramUserId: $telegramUserId) { success } } diff --git a/wondrous-bot-admin/src/graphql/queries/index.ts b/wondrous-bot-admin/src/graphql/queries/index.ts index 60e6260d58..92aa0c0d44 100644 --- a/wondrous-bot-admin/src/graphql/queries/index.ts +++ b/wondrous-bot-admin/src/graphql/queries/index.ts @@ -5,3 +5,4 @@ export * from "./org"; export * from "./payment"; export * from './analytics' export * from "./discord"; +export * from './questSubmission' \ No newline at end of file diff --git a/wondrous-bot-admin/src/graphql/queries/questSubmission.ts b/wondrous-bot-admin/src/graphql/queries/questSubmission.ts new file mode 100644 index 0000000000..ec26d4774d --- /dev/null +++ b/wondrous-bot-admin/src/graphql/queries/questSubmission.ts @@ -0,0 +1,35 @@ +import { gql } from "@apollo/client"; + +export const VERIFY_TWEET_LIKED = gql` + query verifyTweetLiked($cmtyUserId: ID!, $tweetId: String) { + verifyTweetLiked(cmtyUserId: $cmtyUserId, tweetId: $tweetId) { + userLikedTweet + } + } +`; + +export const VERIFY_TWEET_RETWEETED = gql` + query verifyTweetRetweeted($cmtyUserId: ID!, $tweetId: String) { + verifyTweetRetweeted(cmtyUserId: $cmtyUserId, tweetId: $tweetId) { + userRetweetedTweet + } + } +`; + +export const VERIFY_TWITTER_FOLLOW = gql` + query verifyTwitterFollow($cmtyUserId: ID!, $tweetHandle: String) { + verifyTwitterFollow(cmtyUserId: $cmtyUserId, tweetHandle: $tweetHandle) { + userFollowed + } + } +`; + + +export const VERIFY_TWEET_REPLIED = gql` + query verifyTweetReplied($cmtyUserId: ID!, $tweetId: String) { + verifyTweetReplied(cmtyUserId: $cmtyUserId, tweetId: $tweetId) { + userRepliedToTweet + } + } +`; + diff --git a/wondrous-bot-admin/src/pages/twitter/callback/index.tsx b/wondrous-bot-admin/src/pages/twitter/callback/index.tsx index 6bc2c74b46..991bf974ad 100644 --- a/wondrous-bot-admin/src/pages/twitter/callback/index.tsx +++ b/wondrous-bot-admin/src/pages/twitter/callback/index.tsx @@ -10,6 +10,8 @@ const CallbackPage = () => { const code = searchParams?.get("code"); const state = searchParams?.get("state"); const discordId = state?.split("discordId=")[1] || ""; + const telegramUserId = state?.split("telegramUserId=")[1] || ""; + const [finishedVerification, setFinishedVerification] = useState(false); const [errorText, setErrorText] = useState(""); const [verifyTwitter] = useMutation(VERIFY_COMMUNITY_USER_TWITTER, { @@ -24,11 +26,12 @@ const CallbackPage = () => { }, }); useEffect(() => { - if (code && discordId && !finishedVerification) { + if (code && !finishedVerification && (discordId || telegramUserId)) { verifyTwitter({ variables: { code, discordId, + telegramUserId: telegramUserId?.toString(), }, }); } diff --git a/wondrous-bot-admin/src/utils/common.tsx b/wondrous-bot-admin/src/utils/common.tsx index 6c38451e16..026c388b0c 100644 --- a/wondrous-bot-admin/src/utils/common.tsx +++ b/wondrous-bot-admin/src/utils/common.tsx @@ -3,6 +3,10 @@ import moment from "moment"; import { QUEST_CONDITION_TYPES } from "./constants"; import { CHAIN_TO_EXPLORER_URL } from "./web3Constants"; +const DEFAULT_TWITTER_SCOPE = + 'users.read%20tweet.read%20follows.read%20follows.write%20like.read%20like.write%20offline.access'; +export const TWITTER_CHALLENGE_CODE = '0ioze5m20493ny2'; // not that important but should fetch from server' + export function shallowEqual(objA, objB) { if (!objA || !objB) { return objA === objB; @@ -155,3 +159,19 @@ export const toCent = (amount) => { .padEnd(int.length === 1 ? 3 : 4, "0") ); }; + + +export const getTwitterCallbackUrl = () => { + return getBaseUrl() + '%2Ftwitter%2Fcallback'; +}; + +export const buildTwitterAuthUrl = (state?) => { + const CLIENT_ID = 'alotNFdURk5Qd0FoRGpKeUpHMDE6MTpjaQ'; + if (!state) { + state = 'state'; + } + + // fetch URL from server + const redirectUri = getTwitterCallbackUrl(); + return `https://twitter.com/i/oauth2/authorize?client_id=${CLIENT_ID}&scope=${DEFAULT_TWITTER_SCOPE}&response_type=code&redirect_uri=${redirectUri}&state=${state}&code_challenge=${TWITTER_CHALLENGE_CODE}&code_challenge_method=plain`; +}; From ce4a77b8d3651e517ef019a63143d67e76f83c27 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Fri, 1 Sep 2023 23:27:42 +0300 Subject: [PATCH 28/31] twitter stuff --- .../components/QuestSteps/EditModal/index.tsx | 79 --------- .../QuestSteps/QuestStepComponent.tsx | 5 +- .../components/QuestSteps/StepModal/index.tsx | 72 ++++++-- .../Steps/TwitterComponents/index.tsx | 163 ++++++++++++------ .../QuestSteps/Steps/VerifyButton.tsx | 23 +-- .../src/components/QuestSteps/index.tsx | 1 + .../src/components/QuestSteps/styles.tsx | 2 +- .../src/graphql/queries/questSubmission.ts | 8 + .../src/pages/twitter/callback/index.tsx | 4 +- 9 files changed, 192 insertions(+), 165 deletions(-) diff --git a/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx index 8808aa012e..56883f05a5 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx @@ -10,85 +10,6 @@ import { useTakeQuest } from "utils/hooks"; import { Media } from "../Steps/Attachment"; import QuestStepComponent from "../QuestStepComponent"; -const StepContent = ({ response, stepType, dataCollectionType }) => { - const contentTypes = [TYPES.TEXT_FIELD, TYPES.NUMBER]; - - const linkVisits = [ - TYPES.LINK_CLICK, - TYPES.FOLLOW_TWITTER, - TYPES.LIKE_TWEET, - TYPES.LIKE_YT_VIDEO, - TYPES.RETWEET, - TYPES.TWEET_WITH_PHRASE, - TYPES.VERIFY_TOKEN_HOLDING, - TYPES.SUBSCRIBE_YT_CHANNEL, - TYPES.SNAPSHOT_SPACE_VOTE, - TYPES.SNAPSHOT_PROPOSAL_VOTE, - ]; - - if (!response) { - return ( - - Step was skipped - - ); - } - - if (contentTypes?.includes(stepType)) { - return ( - - {response} - - ); - } - if (linkVisits.includes(stepType)) { - return ( - - - Verified URL visit - - ); - } - - if (SELECT_TYPES.includes(stepType)) { - return ( - - {response?.map((value, idx) => ( - {value} - ))} - - ); - } - if (stepType === TYPES.ATTACHMENTS) { - return ( - - {response?.map((media, idx) => { - return ; - })} - - ); - } - if (stepType === TYPES.DATA_COLLECTION) { - const isSkill = dataCollectionType === DATA_COLLECTION_TYPES.SKILLS; - const isInterest = dataCollectionType === DATA_COLLECTION_TYPES.INTERESTS; - return ( - - {response?.map((option, idx) => { - let label = option; - if (isSkill) { - label = SKILLS[option] || option; - } - if (isInterest) { - label = INTERESTS[option] || option; - } - return {label}; - })} - - ); - } - return null; -}; - const QuestStepsList = ({ steps, responses, setEditStepId }) => { const { handleSubmit } = useTakeQuest(); return ( diff --git a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx index 69d7ad00cb..b158bd4884 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx @@ -28,7 +28,7 @@ const COMPONENTS_CONFIG: any = { [TYPES.LIKE_TWEET]: VerifyButton, [TYPES.FOLLOW_TWITTER]: VerifyButton, [TYPES.REPLY_TWEET]: VerifyButton, - [TYPES.REPLY_TWEET]: VerifyButton, + [TYPES.RETWEET]: VerifyButton, [TYPES.TWEET_WITH_PHRASE]: VerifyButton }; @@ -40,8 +40,8 @@ const IMAGES_CONFIG = { const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = false }) => { const Component: React.FC = COMPONENTS_CONFIG[step?.type]; - const [customHandlers, setCustomHandlers] = useState(null); const { onChange, isEditMode } = useTakeQuest(); + if (!isActive || !step) return null; if (Component) { return ( @@ -81,7 +81,6 @@ const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = fal } renderBody={() => ( {IMAGES_CONFIG[step.type] ? : null} {step?.media ? ( diff --git a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx index 02a40ac113..1326d64fe1 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx @@ -6,47 +6,85 @@ import { useMemo } from "react"; import { TYPES } from "utils/constants"; import { useTakeQuest } from "utils/hooks"; +const ContentComponent = ({ link = null, prompt }) => { + return ( + + + {prompt} + + {link ? Link : null} + + ); +}; + const PromptComponent = ({ step }) => { const snapshotVoteTimes = step?.additionalData?.snapshotVoteTimes; + const tweetLink = step?.additionalData?.tweetLink; const tokenName = step?.additionalData?.tokenName; const content = useMemo(() => { if (step.prompt) { return step.prompt; } - if(step.type === TYPES.LINK_CLICK) { - return 'Click on the link below to verify' + if (step.type === TYPES.LINK_CLICK) { + return "Click on the link below to verify"; + } + if (step.type === TYPES.LIKE_YT_VIDEO) { + return "Verify YouTube Like"; } - if(step.type === TYPES.LIKE_YT_VIDEO) { - return 'Verify YouTube Like' + if (step.type === TYPES.SUBSCRIBE_YT_CHANNEL) { + return "Verify YouTube Subscription"; } - if(step.type === TYPES.SUBSCRIBE_YT_CHANNEL) { - return 'Verify YouTube Subscription' + if (step.type === TYPES.SNAPSHOT_PROPOSAL_VOTE) { + return "Please vote on this proposal"; } - if(step.type === TYPES.SNAPSHOT_PROPOSAL_VOTE) { - return 'Please vote on this proposal' + if (step.type === TYPES.SNAPSHOT_SPACE_VOTE) { + return `Please vote in this space at least ${snapshotVoteTimes} times`; } - if(step.type === TYPES.SNAPSHOT_SPACE_VOTE) { - return `Please vote in this space at least ${snapshotVoteTimes} times` + if (step.type === TYPES.VERIFY_TOKEN_HOLDING) { + return `Press to verify ${tokenName || "token"} holdings`; } - if(step.type === TYPES.VERIFY_TOKEN_HOLDING) { - return `Press to verify ${tokenName || 'token'} holdings` + if (step.type === TYPES.LIKE_TWEET) { + return () => ; + } + if (step.type === TYPES.FOLLOW_TWITTER) { + const tweetHandle = step?.additionalData?.tweetHandle; + return ( + + + Follow this account: + + @{tweetHandle} + + ); + } + if(step.type === TYPES.REPLY_TWEET) { + const tweetLink = step?.additionalData?.tweetLink + return () => + } + if(step.type === TYPES.TWEET_WITH_PHRASE) { + const tweetPhrase = step?.additionalData?.tweetPhrase; + return () => + } + if(step.type === TYPES.RETWEET) { + const tweetLink = step?.additionalData?.tweetLink; + return () => } return null; - }, [step.prompt, step.type, snapshotVoteTimes]); + }, [step.prompt, step.type, step?.additionalData]); - return ( + return typeof content === "function" ? ( + content() + ) : ( {content} ); }; -export const StepModal = ({ children, step, disabled, customHandlers }) => { +export const StepModal = ({ children, step, disabled }) => { const { nextStep, isEditMode } = useTakeQuest(); - - return ( diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/TwitterComponents/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/TwitterComponents/index.tsx index 945ca266a6..19e3fec8cc 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/TwitterComponents/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/TwitterComponents/index.tsx @@ -1,84 +1,141 @@ -// step={step} -// startCmtyUserPolling={startPolling} -// stopCmtyUserPolling={stopPolling} -// cmtyUser={data?.getIntegrationCmtyUser} -// handleLinkClick={handleLinkClick} - +import { get } from "lodash"; import { useLazyQuery } from "@apollo/client"; +import { useMemo, useState } from "react"; import { SharedSecondaryButton } from "components/Shared/styles"; -import { VERIFY_TWEET_LIKED } from "graphql/queries"; -import { useMemo } from "react"; import { buildTwitterAuthUrl } from "utils/common"; -import { LinkComponent } from "../LinkComponent"; import { useTakeQuest } from "utils/hooks"; +import { DEFAULT_BANNER_IMAGES, TYPES } from "utils/constants"; +import { Grid } from "@mui/material"; +import { Image } from "components/QuestSteps/styles"; +import { + VERIFY_TWEET_LIKED, + VERIFY_TWEET_REPLIED, + VERIFY_TWEET_RETWEETED, + VERIFY_TWEET_WITH_PHRASE, + VERIFY_TWITTER_FOLLOW, +} from "graphql/queries"; +import { LinkComponent } from "../LinkComponent"; + +const QUERY_MAP = { + [TYPES.LIKE_TWEET]: VERIFY_TWEET_LIKED, + [TYPES.FOLLOW_TWITTER]: VERIFY_TWITTER_FOLLOW, + [TYPES.REPLY_TWEET]: VERIFY_TWEET_REPLIED, + [TYPES.RETWEET]: VERIFY_TWEET_RETWEETED, + [TYPES.TWEET_WITH_PHRASE]: VERIFY_TWEET_WITH_PHRASE, +}; + +const ERRORS_MAP = { + [TYPES.LIKE_TWEET]: "Looks like you haven't liked this tweet yet. Please try again or contact support", + [TYPES.FOLLOW_TWITTER]: "Looks like you haven't followed this account yet. Please try again or contact support", + [TYPES.REPLY_TWEET]: "Looks like you haven't replied to this tweet yet. Please try again or contact support", + [TYPES.RETWEET]: "Looks like you haven't retweeted this tweet yet. Please try again or contact support", + [TYPES.TWEET_WITH_PHRASE]: "Looks like you haven't tweeted with this phrase yet. Please try again or contact support", +}; const TwitterOauth = ({ telegramUserId, callback }) => { const state = `telegramUserId=${telegramUserId}`; const link = buildTwitterAuthUrl(state); - const handleClick = () => { - return callback?.(); - }; - return ( - + Connect Twitter ); }; -export const VerifyLikeTweet = ({ step, startCmtyUserPolling, stopCmtyUserPolling, cmtyUser, handleLinkClick }) => { - const tweetLink = step?.additionalData?.tweetLink; - +const TwitterActionVerifier = ({ step, startCmtyUserPolling, cmtyUser, handleLinkClick, stopCmtyUserPolling }) => { + const [errorCode, setErrorCode] = useState(null); const { nextStep, onChange } = useTakeQuest(); + const query = QUERY_MAP[step.type]; + const [error, setError] = useState(""); + const reconnectTwitterErrors = ["twitter_token_expired", "twitter_missing_scope", "twitter_not_connected"]; + const [invokeQuery, { data, error: errorObj, loading }] = useLazyQuery(query, { + fetchPolicy: "network-only", + nextFetchPolicy: "network-only", + onError: (error) => { + setErrorCode(error?.graphQLErrors[0]?.extensions.errorCode); + }, + }); - const [verifyLikeTweet, { data, error, loading }] = useLazyQuery(VERIFY_TWEET_LIKED); + const getPathToResponse = (type) => { + if (type === TYPES.LIKE_TWEET) return "verifyTweetLiked.userLikedTweet"; + if (type === TYPES.RETWEET) return "verifyTweetRetweeted.userRetweetedTweet"; - const tweetId = tweetLink.split("/").pop(); - const cleanedTweetId = tweetId?.split("?")[0]; + if (type === TYPES.FOLLOW_TWITTER) return "verifyTwitterFollow.userFollowed"; - const handleCallback = () => setTimeout(() => startCmtyUserPolling(1000), 3000); + if (type === TYPES.REPLY_TWEET) return "verifyTweetReplied.userRepliedToTweet"; - const reconnectTwitterErrors = ["twitter_token_expired", "twitter_missing_scope", "twitter_not_connected"]; - const errorCode: any = error?.graphQLErrors[0]?.extensions.errorCode; + if (type === TYPES.TWEET_WITH_PHRASE) return "verifyTweetWithPhrase.userTweetedWithPhrase"; + return ""; + }; + + const errorMessage = useMemo(() => { + if (reconnectTwitterErrors.includes(errorCode)) { + return "Please reconnect your account"; + } + if (!!errorObj) { + return "Something went wrong. Please try again or contact support"; + } + return null; + }, [errorCode, !!errorObj, step.type, data]); if (!cmtyUser?.twitterInfo || reconnectTwitterErrors.includes(errorCode)) { - return ; + return ( + { + setErrorCode(null); + setTimeout(() => startCmtyUserPolling(1000), 3000); + }} + /> + ); } - const handleClick = async () => { - const { data, error } = await verifyLikeTweet({ - variables: { - cmtyUserId: cmtyUser?.id, - tweetId: cleanedTweetId, - }, - }); - if (data?.verifyTweetLiked?.userLikedTweet) { - onChange({ - id: step?.id, - value: true, - }); - return nextStep(); + const generateVariables = () => { + let variables: any = { cmtyUserId: cmtyUser?.id }; + switch (step.type) { + case TYPES.LIKE_TWEET: + case TYPES.RETWEET: + case TYPES.REPLY_TWEET: + const tweetLink = step?.additionalData?.tweetLink; + const tweetId = tweetLink.split("/").pop(); + variables.tweetId = tweetId?.split("?")[0]; + break; + case TYPES.FOLLOW_TWITTER: + variables.tweetHandle = step?.additionalData?.tweetHandle; + break; + case TYPES.TWEET_WITH_PHRASE: + variables.tweetPhrase = step?.additionalData?.tweetPhrase; + break; + default: + break; } + return variables; }; - const errorMessage = useMemo(() => { - if (error?.graphQLErrors && error?.graphQLErrors[0]?.extensions.errorCode === "twitter_not_connected") { - return "Twitter not connected, please connect your twitter account and try again"; + + const handleClick = async () => { + const variables: any = generateVariables(); + setErrorCode(null); + setError(""); + const pathToResponse = getPathToResponse(step.type); + const { data } = await invokeQuery({ variables }); + const value = get(data, pathToResponse); + if (data && value) { + onChange({ id: step?.id, value: true }); + nextStep(); + return; } - if (error?.graphQLErrors && error?.graphQLErrors[0]?.extensions.errorCode === "twitter_missing_scope") { - return "Proposal was not voted on, try again"; + if (value === false) { + setError(ERRORS_MAP[step.type]); } - if (error) { - return "Something went wrong. Please try again or contact support"; - } - return null; - }, [data, error]); + }; - return ; + return ( + + + + + ); }; -export const VerifyFollowAccount = () => null; - -export const VerifyReplyToTweet = () => null; - -export const VerifyRetweet = () => null; +export default TwitterActionVerifier; diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx index ca24897d68..fff331da44 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/VerifyButton.tsx @@ -19,7 +19,7 @@ import { getYouTubeVideoId } from "services/validators/customValidation"; import { getBaseUrl, getWeb3ConnectUrl, getYoutubeChannelId } from "utils/common"; import { TYPES } from "utils/constants"; import { useTakeQuest } from "utils/hooks"; -import { VerifyFollowAccount, VerifyLikeTweet, VerifyReplyToTweet, VerifyRetweet } from "./TwitterComponents"; +import TwitterActionVerifier from "./TwitterComponents"; import { LinkComponent } from "./LinkComponent"; const GoogleVerify = ({ telegramUserId, callback }) => { @@ -382,15 +382,17 @@ const VerifyTokenHoldingButton = ({ step, startCmtyUserPolling, stopCmtyUserPoll setTimeout(() => startCmtyUserPolling(1000), 3000); }; - if (!cmtyUser?.web3Address) { return ; } - return ; + return ( + + ); }; const COMPONENTS = { @@ -400,10 +402,11 @@ const COMPONENTS = { [TYPES.SNAPSHOT_PROPOSAL_VOTE]: SnapshotButton, [TYPES.SNAPSHOT_SPACE_VOTE]: SnapshotButton, [TYPES.VERIFY_TOKEN_HOLDING]: VerifyTokenHoldingButton, - [TYPES.LIKE_TWEET]: VerifyLikeTweet, - [TYPES.FOLLOW_TWITTER]: VerifyFollowAccount, - [TYPES.REPLY_TWEET]: VerifyReplyToTweet, - [TYPES.RETWEET]: VerifyRetweet, + [TYPES.LIKE_TWEET]: TwitterActionVerifier, + [TYPES.FOLLOW_TWITTER]: TwitterActionVerifier, + [TYPES.REPLY_TWEET]: TwitterActionVerifier, + [TYPES.RETWEET]: TwitterActionVerifier, + [TYPES.TWEET_WITH_PHRASE]: TwitterActionVerifier, }; export const VerifyButton = ({ step }) => { diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index 2e02d14ee0..e1080d7b68 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -273,6 +273,7 @@ const QuestStepsList = () => { setActiveStepId(steps[currentStepIdx - 1]?.id); }; + console.log(activeStepId, 'act step id', steps.find(i => i.id === activeStepId), steps) return ( width}; max-height: 200px; `; diff --git a/wondrous-bot-admin/src/graphql/queries/questSubmission.ts b/wondrous-bot-admin/src/graphql/queries/questSubmission.ts index ec26d4774d..f8b9348095 100644 --- a/wondrous-bot-admin/src/graphql/queries/questSubmission.ts +++ b/wondrous-bot-admin/src/graphql/queries/questSubmission.ts @@ -33,3 +33,11 @@ export const VERIFY_TWEET_REPLIED = gql` } `; + +export const VERIFY_TWEET_WITH_PHRASE = gql` + query verifyTweetWithPhrase($cmtyUserId: ID!, $tweetPhrase: String) { + verifyTweetWithPhrase(cmtyUserId: $cmtyUserId, tweetPhrase: $tweetPhrase) { + userTweetedWithPhrase + } + } +`; \ No newline at end of file diff --git a/wondrous-bot-admin/src/pages/twitter/callback/index.tsx b/wondrous-bot-admin/src/pages/twitter/callback/index.tsx index 991bf974ad..bc8d51502b 100644 --- a/wondrous-bot-admin/src/pages/twitter/callback/index.tsx +++ b/wondrous-bot-admin/src/pages/twitter/callback/index.tsx @@ -30,8 +30,8 @@ const CallbackPage = () => { verifyTwitter({ variables: { code, - discordId, - telegramUserId: telegramUserId?.toString(), + ...(discordId && { discordId }), + ...(telegramUserId && { telegramUserId }) }, }); } From f14fbd72b984931555b411a3f3c7593c45e6d833 Mon Sep 17 00:00:00 2001 From: adrian mustea Date: Mon, 4 Sep 2023 15:08:33 +0300 Subject: [PATCH 29/31] fixes --- .../src/components/CreateTemplate/styles.tsx | 1 + .../components/QuestSteps/EditModal/index.tsx | 36 +++++++------------ .../QuestSteps/QuestStepComponent.tsx | 24 ++++++------- .../QuestSteps/Steps/DataCollection.tsx | 5 +++ .../src/components/QuestSteps/Steps/Text.tsx | 10 +++++- .../src/components/QuestSteps/Steps/utils.tsx | 23 ++++++++++++ .../src/components/QuestSteps/index.tsx | 1 - 7 files changed, 63 insertions(+), 37 deletions(-) create mode 100644 wondrous-bot-admin/src/components/QuestSteps/Steps/utils.tsx diff --git a/wondrous-bot-admin/src/components/CreateTemplate/styles.tsx b/wondrous-bot-admin/src/components/CreateTemplate/styles.tsx index 032983181b..a431b262cc 100644 --- a/wondrous-bot-admin/src/components/CreateTemplate/styles.tsx +++ b/wondrous-bot-admin/src/components/CreateTemplate/styles.tsx @@ -8,6 +8,7 @@ export const Panel = styled(Grid)` border-radius: 16px; background: #f7f7f7; width: 100%; + transition: transform 0.2s ease; } `; diff --git a/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx index 56883f05a5..d836412da1 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/EditModal/index.tsx @@ -1,17 +1,13 @@ -import { Box, Divider, Grid, Typography } from "@mui/material"; -import { BotIcon } from "assets/botIcon"; +import { Divider, Grid, Typography } from "@mui/material"; import PanelComponent from "components/CreateTemplate/PanelComponent"; -import { StyledCheckbox } from "components/PaymentLedger/styles"; import { SharedSecondaryButton } from "components/Shared/styles"; -import { StyledContent, StyledViewQuestResults } from "components/ViewQuestResults/styles"; -import { useMemo, useState } from "react"; -import { DATA_COLLECTION_TYPES, INTERESTS, SELECT_TYPES, SKILLS, TYPES } from "utils/constants"; import { useTakeQuest } from "utils/hooks"; -import { Media } from "../Steps/Attachment"; import QuestStepComponent from "../QuestStepComponent"; +import { useEffect } from "react"; -const QuestStepsList = ({ steps, responses, setEditStepId }) => { +const QuestStepsList = ({ steps, responses }) => { const { handleSubmit } = useTakeQuest(); + return ( <> { return ( <> - {idx === steps.length - 1 ? null : } + {idx === steps.length - 1 ? null : ( + + )} ); })} @@ -68,16 +66,8 @@ const QuestStepsList = ({ steps, responses, setEditStepId }) => { const EditModal = ({ responses }) => { const { quest } = useTakeQuest(); const steps = quest?.steps; - const [editStepId, setEditStepId] = useState(null); - const stepToEdit = useMemo(() => { - if (editStepId) { - return steps?.find((step) => step.id === editStepId); - } - return null; - }, [editStepId]); - console.log(stepToEdit, "step to edit", editStepId); - return ; + return ; }; export default EditModal; diff --git a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx index b158bd4884..00a324b80d 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/QuestStepComponent.tsx @@ -29,19 +29,18 @@ const COMPONENTS_CONFIG: any = { [TYPES.FOLLOW_TWITTER]: VerifyButton, [TYPES.REPLY_TWEET]: VerifyButton, [TYPES.RETWEET]: VerifyButton, - [TYPES.TWEET_WITH_PHRASE]: VerifyButton + [TYPES.TWEET_WITH_PHRASE]: VerifyButton, }; const IMAGES_CONFIG = { [TYPES.SNAPSHOT_PROPOSAL_VOTE]: DEFAULT_BANNER_IMAGES.QUEST_STEP_SNAPSHOT, [TYPES.SNAPSHOT_SPACE_VOTE]: DEFAULT_BANNER_IMAGES.QUEST_STEP_SNAPSHOT, - [TYPES.ATTACHMENTS]: DEFAULT_BANNER_IMAGES.ATTACHMENT_REQUIRED, }; const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = false }) => { const Component: React.FC = COMPONENTS_CONFIG[step?.type]; const { onChange, isEditMode } = useTakeQuest(); - + if (!isActive || !step) return null; if (Component) { return ( @@ -50,14 +49,17 @@ const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = fal isEditMode ? { filter: "None;", + className: "quest-step-panel;", + } + : { + className: "quest-step-panel", } - : {} } gridSx={ isEditMode ? { borderRadius: "0px", - padding: '0px' + padding: "0px", } : {} } @@ -80,8 +82,7 @@ const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = fal ) } renderBody={() => ( - + {IMAGES_CONFIG[step.type] ? : null} {step?.media ? ( @@ -90,10 +91,10 @@ const QuestStepComponent = ({ step, value, isActive, nextStepId, isWebView = fal onChange({ id: step.id, value })} placeholder="Enter answer" /> - )} /> diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx index afba2c6547..f9c4193804 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/DataCollection.tsx @@ -8,6 +8,7 @@ import { DATA_COLLECTION_TYPES, TYPES } from "utils/constants"; import AddIcon from "@mui/icons-material/Add"; import AutocompleteOptionsComponent from "components/AddFormEntity/components/AutocompleteComponent"; import countries from "utils/countries"; +import { useKeyboardEffect } from "./utils"; const SelectOption = ({ step, onChange, value = [] }) => { const [inputValue, setInputValue] = useState(""); @@ -44,6 +45,8 @@ const SelectOption = ({ step, onChange, value = [] }) => { } }; + const { onBlur, onFocus } = useKeyboardEffect(); + return ( {allOptions.map((option, idx) => { @@ -76,6 +79,8 @@ const SelectOption = ({ step, onChange, value = [] }) => { onChange={handleInputChange} value={inputValue} placeholder={"Enter your option"} + onBlur={onBlur} + onFocus={onFocus} /> { if (type === "number" || type === "tel") { @@ -20,6 +22,10 @@ export const StepTextField = ({ step, onChange, value, placeholder = "", type = } }; + const { onBlur, onFocus } = useKeyboardEffect(); + + const {isEditMode} = useTakeQuest(); + return ( <> @@ -29,7 +35,9 @@ export const StepTextField = ({ step, onChange, value, placeholder = "", type = onChange={handleInputChange} value={value} placeholder={placeholder} - autoFocus="true" + autoFocus={!isEditMode} + onFocus={onFocus} + onBlur={onBlur} /> diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/utils.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/utils.tsx new file mode 100644 index 0000000000..5570575f92 --- /dev/null +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/utils.tsx @@ -0,0 +1,23 @@ +export const useKeyboardEffect = () => { + const WebApp = (window as any).Telegram; + const platform = WebApp?.WebView?.initParams?.tgWebAppPlatform; + const isMobilePlatform = platform === "ios" || platform === "android"; + + const handleInputFocus = (type) => { + if (!isMobilePlatform) return; + const panel = document.querySelector(".quest-step-panel"); + if (panel instanceof HTMLElement) { + if (type === "in") { + panel.style.transform = "translateY(-20%)"; + } else { + panel.style.transform = "translateY(0)"; + } + } + }; + + return { + handleInputFocus, + onBlur: (e) => handleInputFocus("out"), + onFocus: (e) => handleInputFocus("in"), + }; +}; diff --git a/wondrous-bot-admin/src/components/QuestSteps/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/index.tsx index e1080d7b68..2e02d14ee0 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/index.tsx @@ -273,7 +273,6 @@ const QuestStepsList = () => { setActiveStepId(steps[currentStepIdx - 1]?.id); }; - console.log(activeStepId, 'act step id', steps.find(i => i.id === activeStepId), steps) return ( Date: Mon, 4 Sep 2023 15:43:20 +0300 Subject: [PATCH 30/31] text wrap --- .../components/QuestSteps/StepModal/index.tsx | 25 +++++++++++++------ .../src/components/QuestSteps/Steps/Text.tsx | 3 ++- .../src/components/Shared/TextField.tsx | 4 +-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx index 1326d64fe1..45ea34e112 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/StepModal/index.tsx @@ -58,17 +58,17 @@ const PromptComponent = ({ step }) => { ); } - if(step.type === TYPES.REPLY_TWEET) { - const tweetLink = step?.additionalData?.tweetLink - return () => + if (step.type === TYPES.REPLY_TWEET) { + const tweetLink = step?.additionalData?.tweetLink; + return () => ; } - if(step.type === TYPES.TWEET_WITH_PHRASE) { + if (step.type === TYPES.TWEET_WITH_PHRASE) { const tweetPhrase = step?.additionalData?.tweetPhrase; - return () => + return () => ; } - if(step.type === TYPES.RETWEET) { + if (step.type === TYPES.RETWEET) { const tweetLink = step?.additionalData?.tweetLink; - return () => + return () => ; } return null; }, [step.prompt, step.type, step?.additionalData]); @@ -76,7 +76,16 @@ const PromptComponent = ({ step }) => { return typeof content === "function" ? ( content() ) : ( - + {content} ); diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx index c321f2095f..8473a7fbf2 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/Text.tsx @@ -26,6 +26,7 @@ export const StepTextField = ({ step, onChange, value, placeholder = "", type = const {isEditMode} = useTakeQuest(); + const shouldAutoFocus = step.order > 1 && !isEditMode; return ( <> @@ -35,7 +36,7 @@ export const StepTextField = ({ step, onChange, value, placeholder = "", type = onChange={handleInputChange} value={value} placeholder={placeholder} - autoFocus={!isEditMode} + autoFocus={shouldAutoFocus} onFocus={onFocus} onBlur={onBlur} /> diff --git a/wondrous-bot-admin/src/components/Shared/TextField.tsx b/wondrous-bot-admin/src/components/Shared/TextField.tsx index 2c4034325b..61d6ea9fd4 100644 --- a/wondrous-bot-admin/src/components/Shared/TextField.tsx +++ b/wondrous-bot-admin/src/components/Shared/TextField.tsx @@ -1,5 +1,5 @@ import { Box } from "@mui/material"; -import { memo } from "react"; +import { memo, useEffect, useRef } from "react"; import { CustomTextField } from "../AddFormEntity/components/styles"; import { ErrorText } from "./styles"; @@ -15,7 +15,7 @@ const TextFieldComponent = ({ const handleChange = (e) => { return onChange(e.target.value); }; - + return ( Date: Mon, 4 Sep 2023 16:40:02 +0300 Subject: [PATCH 31/31] keyboard effect --- wondrous-bot-admin/src/components/QuestSteps/Steps/utils.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wondrous-bot-admin/src/components/QuestSteps/Steps/utils.tsx b/wondrous-bot-admin/src/components/QuestSteps/Steps/utils.tsx index 5570575f92..76357996a3 100644 --- a/wondrous-bot-admin/src/components/QuestSteps/Steps/utils.tsx +++ b/wondrous-bot-admin/src/components/QuestSteps/Steps/utils.tsx @@ -7,9 +7,13 @@ export const useKeyboardEffect = () => { if (!isMobilePlatform) return; const panel = document.querySelector(".quest-step-panel"); if (panel instanceof HTMLElement) { + const container = panel?.parentElement; + if(!container) return; if (type === "in") { + container.style.paddingTop = '50%'; panel.style.transform = "translateY(-20%)"; } else { + container.style.paddingTop = '0'; panel.style.transform = "translateY(0)"; } }