diff --git a/wondrous-bot-admin/public/images/banner-images/leaderboard-banner.png b/wondrous-bot-admin/public/images/banner-images/leaderboard-banner.png
new file mode 100644
index 0000000000..e275a0daa4
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/leaderboard-banner.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/leaderboard-circle.png b/wondrous-bot-admin/public/images/banner-images/leaderboard-circle.png
new file mode 100644
index 0000000000..ad99936dc6
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/leaderboard-circle.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/my-level-banner.png b/wondrous-bot-admin/public/images/banner-images/my-level-banner.png
new file mode 100644
index 0000000000..cfa7b08119
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/my-level-banner.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/my-level-circle.png b/wondrous-bot-admin/public/images/banner-images/my-level-circle.png
new file mode 100644
index 0000000000..33bfb7e17d
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/my-level-circle.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/my-purchases-banner.png b/wondrous-bot-admin/public/images/banner-images/my-purchases-banner.png
new file mode 100644
index 0000000000..c3256cfc62
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/my-purchases-banner.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/my-purchases-circle.png b/wondrous-bot-admin/public/images/banner-images/my-purchases-circle.png
new file mode 100644
index 0000000000..8eb363266a
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/my-purchases-circle.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/onboard-me-banner.png b/wondrous-bot-admin/public/images/banner-images/onboard-me-banner.png
new file mode 100644
index 0000000000..f687753cd4
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/onboard-me-banner.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/onboard-me-circle.png b/wondrous-bot-admin/public/images/banner-images/onboard-me-circle.png
new file mode 100644
index 0000000000..10b28fa086
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/onboard-me-circle.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/quest-banner.png b/wondrous-bot-admin/public/images/banner-images/quest-banner.png
new file mode 100644
index 0000000000..31216c65f7
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/quest-banner.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/quest-circle.png b/wondrous-bot-admin/public/images/banner-images/quest-circle.png
new file mode 100644
index 0000000000..fafe237d73
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/quest-circle.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/store-banner.png b/wondrous-bot-admin/public/images/banner-images/store-banner.png
new file mode 100644
index 0000000000..eb51f1548e
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/store-banner.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/store-circle.png b/wondrous-bot-admin/public/images/banner-images/store-circle.png
new file mode 100644
index 0000000000..1967b31ef1
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/store-circle.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/sub-banner.png b/wondrous-bot-admin/public/images/banner-images/sub-banner.png
new file mode 100644
index 0000000000..cc2758a51a
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/sub-banner.png differ
diff --git a/wondrous-bot-admin/public/images/banner-images/sub-circle.png b/wondrous-bot-admin/public/images/banner-images/sub-circle.png
new file mode 100644
index 0000000000..c1dd8c39b6
Binary files /dev/null and b/wondrous-bot-admin/public/images/banner-images/sub-circle.png differ
diff --git a/wondrous-bot-admin/src/App.tsx b/wondrous-bot-admin/src/App.tsx
index 8b83a8d12a..3c33405769 100644
--- a/wondrous-bot-admin/src/App.tsx
+++ b/wondrous-bot-admin/src/App.tsx
@@ -24,6 +24,7 @@ import { WonderWeb3Provider } from "utils/context/WonderWeb3Context";
import SettingsPage from "pages/settings";
import TeamSettingsPage from "pages/settings/team";
import BillingPage from "pages/settings/billing";
+import CustomizeBannersPage from "pages/settings/customize-banners";
import NotificationSettingsPage from "pages/settings/notification";
import WalletConnectPage from "pages/wallet/connect";
import OnboardingPage from "pages/onboarding";
@@ -119,6 +120,10 @@ const router = createBrowserRouter([
path: "/settings/nft",
element: ,
},
+ {
+ path: "/settings/customize-banners",
+ element: ,
+ },
{
path: "/",
element: ,
diff --git a/wondrous-bot-admin/src/components/ImageUpload/AvatarEditor/index.tsx b/wondrous-bot-admin/src/components/ImageUpload/AvatarEditor/index.tsx
index 8c3b27fcec..e4e3752f18 100644
--- a/wondrous-bot-admin/src/components/ImageUpload/AvatarEditor/index.tsx
+++ b/wondrous-bot-admin/src/components/ImageUpload/AvatarEditor/index.tsx
@@ -1,20 +1,17 @@
-import { useEffect, useRef, useState } from 'react';
-
-import max from 'lodash/max';
-import DefaultAvatarEditor from 'react-avatar-editor';
-
-import { AvatarEditorTypes } from 'types/assets';
-import {
- ButtonIconWrapper,
- SharedSecondaryButton,
-} from 'components/Shared/styles';
-import Modal from 'components/Shared/Modal';
-import { Box, Grid } from '@mui/material';
-import { pinkColors } from 'utils/theme/colors';
-import ReplaceIcon from 'components/Icons/ReplaceIcon';
-import DeleteIcon from 'components/Icons/Delete';
-import { Label } from 'components/CreateTemplate/styles';
-import { ZoomIn, ZoomOut } from '@mui/icons-material';
+import { useEffect, useRef, useState } from "react";
+
+import max from "lodash/max";
+import DefaultAvatarEditor from "react-avatar-editor";
+
+import { AvatarEditorTypes } from "types/assets";
+import { ButtonIconWrapper, SharedSecondaryButton } from "components/Shared/styles";
+import Modal from "components/Shared/Modal";
+import { Box, Grid } from "@mui/material";
+import { pinkColors } from "utils/theme/colors";
+import ReplaceIcon from "components/Icons/ReplaceIcon";
+import DeleteIcon from "components/Icons/Delete";
+import { Label } from "components/CreateTemplate/styles";
+import { ZoomIn, ZoomOut } from "@mui/icons-material";
type Props = {
originalImage: string | File;
@@ -25,7 +22,7 @@ type Props = {
clearInput: () => void;
imageType: AvatarEditorTypes;
title: string;
- recommendDateionText: string;
+ recommendDateionText?: string;
};
interface ImageViewerObjectProps {
@@ -34,6 +31,29 @@ interface ImageViewerObjectProps {
borderRadius: number;
}
+const IMAGE_VIEWER_SIZE: Record = {
+ HEADER_IMAGE: {
+ width: 550,
+ height: 78,
+ borderRadius: 0,
+ },
+ ICON_IMAGE: {
+ width: 250,
+ height: 250,
+ borderRadius: 250,
+ },
+ BANNER_IMAGE: {
+ width: 640,
+ height: 140,
+ borderRadius: 0,
+ },
+ BANNER_LOGO_IMAGE: {
+ width: 400,
+ height: 400,
+ borderRadius: 0,
+ },
+};
+
const AvatarEditor = ({
originalImage,
open,
@@ -50,18 +70,7 @@ const AvatarEditor = ({
const [angle, setAngle] = useState(0);
const editorRef = useRef(null);
- const imageViewerSize: Record = {
- HEADER_IMAGE: {
- width: 550,
- height: 78,
- borderRadius: 0,
- },
- ICON_IMAGE: {
- width: 250,
- height: 250,
- borderRadius: 250,
- },
- };
+ const currentImageViewerSize = IMAGE_VIEWER_SIZE[imageType];
useEffect(() => {
setScale(1.0);
@@ -83,27 +92,27 @@ const AvatarEditor = ({
// Event handlers
const onAction = (action) => {
switch (action) {
- case 'zoom_in':
+ case "zoom_in":
setScale(scale + defaultZoomScale);
break;
- case 'zoom_out':
+ case "zoom_out":
setScale(max([scale - defaultZoomScale, maxZoomOut]) || maxZoomOut);
break;
- case 'rotate_right':
+ case "rotate_right":
setAngle(angle + defaultRotateAngle);
break;
- case 'rotate_left':
+ case "rotate_left":
setAngle(angle - defaultRotateAngle);
break;
- case 'crop':
+ case "crop":
break;
default:
- throw new Error('Unknown action');
+ throw new Error("Unknown action");
}
};
@@ -125,95 +134,89 @@ const AvatarEditor = ({
const file = new File([blob], `profile-pic.${blob.type.substring(6)}`, {
type: blob.type,
});
+ console.log("fetch file", file);
onSave([file]);
});
};
+ const maxWidth =
+ currentImageViewerSize.width > currentImageViewerSize.height
+ ? currentImageViewerSize.width * 1.5
+ : currentImageViewerSize.width * 2;
+
return (
Cancel
}
- footerRight={
-
- Confirm image
-
- }
+ footerRight={Confirm image}
+ modalFooterStyle={{
+ gap: "8px",
+ }}
>
-
-
+
+
-
-
-
+
+
+
Replace image
-
+
Delete image
-
- onAction('zoom_in')}>
+
+ onAction("zoom_in")}>
- onAction('zoom_out')}>
+ onAction("zoom_out")}>
-
-
+
+
);
};
-export const AVATAR_EDITOR_TYPES: Record =
- {
- HEADER_IMAGE: 'HEADER_IMAGE',
- ICON_IMAGE: 'ICON_IMAGE',
- };
+export const AVATAR_EDITOR_TYPES: Record = {
+ HEADER_IMAGE: "HEADER_IMAGE",
+ ICON_IMAGE: "ICON_IMAGE",
+ BANNER_IMAGE: "BANNER_IMAGE",
+ BANNER_LOGO_IMAGE: "BANNER_LOGO_IMAGE",
+};
export default AvatarEditor;
diff --git a/wondrous-bot-admin/src/components/Settings/CustomizeBanners/index.tsx b/wondrous-bot-admin/src/components/Settings/CustomizeBanners/index.tsx
new file mode 100644
index 0000000000..ff2335b7ab
--- /dev/null
+++ b/wondrous-bot-admin/src/components/Settings/CustomizeBanners/index.tsx
@@ -0,0 +1,488 @@
+import { Box } from "@mui/material";
+import DeleteIcon from "components/Icons/Delete";
+import { useContext, useRef, useState } from "react";
+import { ButtonIconWrapper } from "components/Shared/styles";
+import ReplaceIcon from "components/Icons/ReplaceIcon";
+import {
+ CommandBannerContainer,
+ HeaderText,
+ HeaderContainer,
+ BannerUploadText,
+ BannerUploadButtonContainer,
+ BannerUploadTextButtonContainer,
+ TopImageTextButtonContainer,
+ TopImageText,
+ CommandBannerUploadContainer,
+ TopImageSectionContainer,
+ TopImageImageButtonContainer,
+ TopImageButtonContainer,
+ SectionDivider,
+ CustomizeBannersContainer,
+ BannerUploadHeader,
+ BannerUploadContainer,
+ CommandsContainer,
+ HeaderContainerTooltipContent,
+ BannerUploadImageContainer,
+ TopImageContainer,
+ ButtonInputContainer,
+} from "./styles";
+import { StyledInformationTooltip } from "components/Shared/Tooltip";
+import InformationTooltip from "components/Icons/information.svg";
+import { DELETE_ORG_BANNER, UPSERT_ORG_CUSTOM_BANNER } from "graphql/mutations/orgAsset";
+import { useMutation, useQuery } from "@apollo/client";
+import GlobalContext from "utils/context/GlobalContext";
+import { transformAndUploadMedia } from "utils/media";
+import { GET_ORG_CUSTOM_ASSETS } from "graphql/queries/orgAsset";
+import SafeImage from "components/SafeImage";
+import useAlerts, { useSubscriptionPaywall } from "utils/hooks";
+import { useNavigate } from "react-router-dom";
+import AvatarEditor, { AVATAR_EDITOR_TYPES } from "components/ImageUpload/AvatarEditor";
+
+const EXEMPTED_ORG_IDS = ["911445364593262592", "844677430694510634", "1192224585215639572"];
+
+const ORG_ASSET_PURPOSE = {
+ questBanner: "quest_banner",
+ levelBanner: "level_banner",
+ leaderboardBanner: "leaderboard_banner",
+ startQuestBanner: "start_quest_banner",
+ mySubmissionBanner: "my_submission_banner",
+ storeBanner: "store_banner",
+ myPurchasesBanner: "my_purchases_banner",
+ onboardMeBanner: "onboard_me_banner",
+ referralBanner: "referral_banner",
+ questLogo: "quest_logo",
+ levelLogo: "level_logo",
+ leaderboardLogo: "leaderboard_logo",
+ mySubmissionLogo: "my_submission_logo",
+ storeLogo: "store_logo",
+ myPurchasesLogo: "my_purchases_logo",
+ onboardMeLogo: "onboard_me_logo",
+ referralLogo: "referral_logo",
+};
+
+const commandBanners: {
+ title: string;
+ tooltip: string;
+ banner: {
+ purpose: (typeof ORG_ASSET_PURPOSE)[keyof typeof ORG_ASSET_PURPOSE];
+ image: string;
+ };
+ logo: {
+ purpose: (typeof ORG_ASSET_PURPOSE)[keyof typeof ORG_ASSET_PURPOSE];
+ image: string;
+ };
+}[] = [
+ {
+ title: "Quests",
+ tooltip: "Quests are a series of tasks that users can complete to earn rewards.",
+ banner: {
+ purpose: ORG_ASSET_PURPOSE.questBanner,
+ image: "/images/banner-images/quest-banner.png",
+ },
+ logo: {
+ purpose: ORG_ASSET_PURPOSE.questLogo,
+ image: "/images/banner-images/quest-circle.png",
+ },
+ },
+
+ {
+ title: "My Submissions",
+ tooltip: "View all of your submissions and their statuses.",
+ banner: {
+ purpose: ORG_ASSET_PURPOSE.mySubmissionBanner,
+ image: "/images/banner-images/sub-banner.png",
+ },
+ logo: {
+ purpose: ORG_ASSET_PURPOSE.mySubmissionLogo,
+ image: "/images/banner-images/sub-circle.png",
+ },
+ },
+ {
+ title: "My Level",
+ tooltip: "View your current level and experience points.",
+ banner: {
+ purpose: ORG_ASSET_PURPOSE.levelBanner,
+ image: "/images/banner-images/my-level-banner.png",
+ },
+ logo: {
+ purpose: ORG_ASSET_PURPOSE.levelLogo,
+ image: "/images/banner-images/my-level-circle.png",
+ },
+ },
+ {
+ title: "Leaderboard",
+ tooltip: "View the top users and their levels.",
+ banner: {
+ purpose: ORG_ASSET_PURPOSE.leaderboardBanner,
+ image: "/images/banner-images/leaderboard-banner.png",
+ },
+ logo: {
+ purpose: ORG_ASSET_PURPOSE.leaderboardLogo,
+ image: "/images/banner-images/leaderboard-circle.png",
+ },
+ },
+ {
+ title: "Store",
+ tooltip: "View all of the items available for purchase.",
+ banner: {
+ purpose: ORG_ASSET_PURPOSE.storeBanner,
+ image: "/images/banner-images/store-banner.png",
+ },
+ logo: {
+ purpose: ORG_ASSET_PURPOSE.storeLogo,
+ image: "/images/banner-images/store-circle.png",
+ },
+ },
+ {
+ title: "My Purchases",
+ tooltip: "View all of your purchases.",
+ banner: {
+ purpose: ORG_ASSET_PURPOSE.myPurchasesBanner,
+ image: "/images/banner-images/my-purchases-banner.png",
+ },
+ logo: {
+ purpose: ORG_ASSET_PURPOSE.myPurchasesLogo,
+ image: "/images/banner-images/my-purchases-circle.png",
+ },
+ },
+ {
+ title: "Onboard Me",
+ tooltip: "Complete the onboarding process.",
+ banner: {
+ purpose: ORG_ASSET_PURPOSE.onboardMeBanner,
+ image: "/images/banner-images/onboard-me-banner.png",
+ },
+ logo: {
+ purpose: ORG_ASSET_PURPOSE.onboardMeLogo,
+ image: "/images/banner-images/onboard-me-circle.png",
+ },
+ },
+];
+
+const CommandBanner = ({
+ baseBanner,
+ customBanner,
+ handleReplaceImage,
+ handleDeleteImage,
+ setSelectedAvatarProps,
+ setTempImage,
+ handleResetAvatarImage,
+}) => {
+ const { title, tooltip, banner, logo } = baseBanner;
+ const bannerImageInputField = useRef(null);
+ const topImageInputField = useRef(null);
+
+ const customBannerImage = customBanner?.find((customBanner) => customBanner.purpose === banner.purpose);
+ const customTopImage = customBanner?.find((customBanner) => customBanner.purpose === logo.purpose);
+ const customBannerImageUrl = customBannerImage?.publicUrl;
+ const customTopImageUrl = customTopImage?.publicUrl;
+
+ const handleDeleteBannerImage = async () => {
+ handleDeleteImage({
+ assetId: customBannerImage?.id,
+ imageInputField: bannerImageInputField,
+ });
+ };
+
+ const handleDeleteTopImage = async () => {
+ handleDeleteImage({
+ assetId: customTopImage?.id,
+ imageInputField: topImageInputField,
+ });
+ };
+
+ const handleOnSave = async ({ file, replaceImageCallback }) => {
+ if (!file) {
+ handleResetAvatarImage();
+ return;
+ }
+ replaceImageCallback();
+ handleResetAvatarImage();
+ };
+
+ const handleSetBannerImageAvatarProps = () => {
+ if (bannerImageInputField.current.value === "") {
+ bannerImageInputField.current.click();
+ return;
+ }
+ setSelectedAvatarProps({
+ originalImage: customBannerImageUrl || banner.image,
+ open: true,
+ openSelectFile: () => bannerImageInputField.current.click(),
+ imageType: AVATAR_EDITOR_TYPES.BANNER_IMAGE,
+ onSave: async (file: File) =>
+ handleOnSave({
+ file,
+ replaceImageCallback: async () =>
+ await handleReplaceImage({ file, purpose: banner.purpose, imageInputField: bannerImageInputField }),
+ }),
+ onCancel: () => (bannerImageInputField.current.value = ""),
+ });
+ };
+
+ const handleBannerImageOnChange = (e) => {
+ setTempImage(e.target.files[0]);
+ handleSetBannerImageAvatarProps();
+ };
+
+ const handleSetTopImageAvatarProps = (logo) => {
+ if (topImageInputField.current.value === "") {
+ topImageInputField.current.click();
+ return;
+ }
+ setSelectedAvatarProps({
+ originalImage: customTopImageUrl || logo.image,
+ open: true,
+ openSelectFile: () => topImageInputField.current.click(),
+ imageType: AVATAR_EDITOR_TYPES.BANNER_LOGO_IMAGE,
+ onSave: async (file: File) =>
+ handleOnSave({
+ file,
+ replaceImageCallback: async () =>
+ await handleReplaceImage({ file, purpose: logo.purpose, imageInputField: topImageInputField }),
+ }),
+ onCancel: () => (topImageInputField.current.value = ""),
+ });
+ };
+
+ const handleSetTopImageOnChange = (e) => {
+ setTempImage(e.target.files[0]);
+ handleSetTopImageAvatarProps(logo);
+ };
+
+ return (
+
+
+
+
+ /{title}
+
+
+
+
+
+
+
+
+ Banner
+
+ {customBannerImageUrl ? (
+
+ ) : (
+
+ )}
+
+
+ Optimal size: 640 x 140px
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Top Image
+
+
+ {customTopImageUrl ? (
+
+ ) : (
+
+ )}
+
+
+ 400 x 400px
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const CustomizeBanners = () => {
+ const navigate = useNavigate();
+ const { activeOrg } = useContext(GlobalContext);
+ const { isLoading, isPremiumPlan, isEcosystemPlan, setPaywall, setPaywallMessage, setOnCancel, setCanBeClosed } =
+ useSubscriptionPaywall();
+ const { data } = useQuery(GET_ORG_CUSTOM_ASSETS, {
+ variables: {
+ orgId: activeOrg?.id,
+ },
+ skip: !activeOrg?.id,
+ });
+ const { setSnackbarAlertMessage, setSnackbarAlertOpen, setSnackbarAlertSeverity, showError } = useAlerts();
+ const [updateBanner] = useMutation(UPSERT_ORG_CUSTOM_BANNER);
+ const [deleteBanner] = useMutation(DELETE_ORG_BANNER);
+
+ const defaultAvatarProps = {
+ originalImage: null,
+ open: false,
+ onCancel: () => {},
+ };
+ const [selectedAvatarProps, setSelectedAvatarProps] = useState(defaultAvatarProps);
+ const [tempImage, setTempImage] = useState(null);
+ const handleResetAvatarImage = () => {
+ selectedAvatarProps?.onCancel();
+ setTempImage(null);
+ setSelectedAvatarProps(defaultAvatarProps);
+ };
+
+ if (isLoading || !(isPremiumPlan || isEcosystemPlan) || EXEMPTED_ORG_IDS.includes(activeOrg?.id)) {
+ setOnCancel(() => {
+ return () => {
+ setPaywall(false);
+ setPaywallMessage("");
+ setOnCancel(null);
+ setCanBeClosed(true);
+ navigate(-1);
+ };
+ });
+ setPaywallMessage("Customize Banners");
+ setPaywall(true);
+ return null;
+ }
+
+ if (isEcosystemPlan || isPremiumPlan) {
+ setPaywall(false);
+ }
+
+ const handleReplaceImage = async ({ file, purpose, imageInputField }) => {
+ console.log("purpose", purpose);
+ const image = file[0];
+
+ if (!image || !image.type.includes("image")) {
+ showError("Invalid file type");
+ return;
+ }
+
+ const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
+ if (image.size > MAX_FILE_SIZE) {
+ showError("File size should be less than 5MB");
+ return;
+ }
+
+ const { filename } = await transformAndUploadMedia({
+ file: image,
+ });
+
+ await updateBanner({
+ variables: {
+ input: {
+ orgId: activeOrg?.id,
+ purpose,
+ mediaUpload: {
+ uploadSlug: filename,
+ },
+ },
+ },
+ refetchQueries: [GET_ORG_CUSTOM_ASSETS],
+ onCompleted: () => {
+ imageInputField.current.value = "";
+ setSnackbarAlertSeverity("success");
+ setSnackbarAlertMessage("Updated successfully");
+ setSnackbarAlertOpen(true);
+ },
+ onError: () => {
+ showError("Error updating image");
+ },
+ });
+ };
+
+ const handleDeleteImage = async ({ assetId, imageInputField }) => {
+ const onCompleted = () => {
+ imageInputField.current.value = "";
+ setSnackbarAlertSeverity("success");
+ setSnackbarAlertMessage("Deleted successfully");
+ setSnackbarAlertOpen(true);
+ return;
+ };
+ if (!assetId) {
+ onCompleted();
+ return;
+ }
+ await deleteBanner({
+ variables: {
+ orgAssetId: assetId,
+ },
+ refetchQueries: [GET_ORG_CUSTOM_ASSETS],
+ onCompleted,
+ onError: () => {
+ showError("Error deleting image");
+ },
+ });
+ };
+
+ return (
+ <>
+ {}}
+ openSelectFile={() => {}}
+ imageType={AVATAR_EDITOR_TYPES.BANNER_IMAGE}
+ title={"Upload Image"}
+ {...selectedAvatarProps}
+ originalImage={tempImage || selectedAvatarProps?.originalImage}
+ onCancel={handleResetAvatarImage}
+ clearInput={() => setSelectedAvatarProps(selectedAvatarProps)}
+ />
+
+
+ {commandBanners.map((banner) => {
+ return (
+
+ );
+ })}
+
+
+ >
+ );
+};
+
+export default CustomizeBanners;
diff --git a/wondrous-bot-admin/src/components/Settings/CustomizeBanners/styles.tsx b/wondrous-bot-admin/src/components/Settings/CustomizeBanners/styles.tsx
new file mode 100644
index 0000000000..a73fdc35ae
--- /dev/null
+++ b/wondrous-bot-admin/src/components/Settings/CustomizeBanners/styles.tsx
@@ -0,0 +1,205 @@
+import { Box, Divider, Grid, Typography } from "@mui/material";
+import styled from "styled-components";
+
+export const CustomizeBannersContainer = styled((props) => )`
+ && {
+ display: flex;
+ flex: 1;
+ }
+`;
+
+export const CommandsContainer = styled((props) => )`
+ && {
+ justify-content: center;
+ gap: 24px;
+ }
+
+ ${({ theme }) => theme.breakpoints.up("xl")} {
+ && {
+ justify-content: flex-start;
+ }
+ }
+`;
+
+export const CommandBannerContainer = styled(Grid)`
+ && {
+ background-color: white;
+ color: #4d4d4d;
+ border-radius: 16px;
+ width: 100%;
+ }
+
+ ${({ theme }) => theme.breakpoints.up("sm")} {
+ max-width: 448px;
+ }
+`;
+
+export const HeaderContainer = styled(Grid)`
+ && {
+ border-bottom: 1px solid #e0e0e0;
+ margin: 14px;
+ margin-bottom: 0;
+ }
+`;
+
+export const HeaderContainerTooltipContent = styled(Grid)`
+ && {
+ display: flex;
+ gap: 8px;
+ width: fit-content;
+ }
+`;
+
+export const HeaderText = styled(Typography)`
+ && {
+ padding-bottom: 8px;
+ font-size: 13px;
+ font-weight: 600;
+ }
+`;
+
+export const CommandBannerUploadContainer = styled(Grid)`
+ ${({ theme }) => theme.breakpoints.up("lg")} {
+ display: flex;
+ }
+`;
+
+export const BannerUploadContainer = styled(Grid)`
+ && {
+ padding: 14px;
+ flex: 1;
+ }
+`;
+
+export const BannerUploadHeader = styled(Typography)`
+ && {
+ font-size: 13px;
+ font-weight: 600;
+ padding-bottom: 12px;
+ }
+`;
+
+export const BannerUploadImageContainer = styled(Grid)`
+ && {
+ height: 70px;
+ width: 100%;
+ border-radius: 6px;
+ overflow: hidden;
+ }
+
+ && > img {
+ height: 100%;
+ width: 100%;
+ object-fit: cover;
+ }
+`;
+
+export const BannerUploadTextButtonContainer = styled(Grid)`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 12px;
+ padding-top: 12px;
+
+ ${({ theme }) => theme.breakpoints.up("md")} {
+ && {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+ }
+`;
+
+export const BannerUploadText = styled(Typography)`
+ && {
+ font-size: 11px;
+ font-weight: 500;
+ width: fit-content;
+ }
+`;
+
+export const BannerUploadButtonContainer = styled(Grid)`
+ width: fit-content;
+ display: flex;
+ gap: 8px;
+`;
+
+export const ButtonInputContainer = styled(Grid)`
+ && {
+ position: absolute;
+
+ & > input {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ opacity: 0;
+ }
+ }
+`;
+
+export const SectionDivider = styled(Divider)`
+ ${({ theme }) => theme.breakpoints.up("md")} {
+ display: none;
+ }
+`;
+
+export const TopImageSectionContainer = styled(Grid)`
+ && {
+ padding: 14px;
+ display: flex;
+ flex-direction: column;
+ }
+
+ ${({ theme }) => theme.breakpoints.up("md")} {
+ && {
+ flex-direction: column;
+ }
+ }
+`;
+
+export const TopImageImageButtonContainer = styled(Grid)`
+ display: flex;
+ gap: 12px;
+
+ ${({ theme }) => theme.breakpoints.up("md")} {
+ && {
+ flex-direction: column;
+ }
+ }
+`;
+
+export const TopImageContainer = styled(Grid)`
+ && {
+ height: 70px;
+ width: 70px;
+ border-radius: 1000px;
+ overflow: hidden;
+ }
+ && > img {
+ height: 100%;
+ width: 100%;
+ object-fit: cover;
+ }
+`;
+
+export const TopImageTextButtonContainer = styled(Grid)`
+ && {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ }
+`;
+
+export const TopImageText = styled(Typography)`
+ && {
+ font-weight: 500;
+ font-size: 11px;
+ }
+`;
+
+export const TopImageButtonContainer = styled(Grid)`
+ display: flex;
+ gap: 8px;
+`;
diff --git a/wondrous-bot-admin/src/components/Settings/MenuSwitcher.tsx b/wondrous-bot-admin/src/components/Settings/MenuSwitcher.tsx
index edbafa6ed4..a32edf5757 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: "General Settings",
path: "/settings",
},
+ {
+ title: "Customize Banners",
+ path: "/settings/customize-banners",
+ },
{
title: "Notifications",
path: "/settings/notifications",
diff --git a/wondrous-bot-admin/src/components/Shared/Modal/index.tsx b/wondrous-bot-admin/src/components/Shared/Modal/index.tsx
index 17035d2622..e48559bcb2 100644
--- a/wondrous-bot-admin/src/components/Shared/Modal/index.tsx
+++ b/wondrous-bot-admin/src/components/Shared/Modal/index.tsx
@@ -29,6 +29,7 @@ interface IModalProps {
dialogComponentProps?: any;
modalFooterStyle?: {
padding?: string;
+ gap?: string;
};
modalTitleStyle?: any;
closeButtonStyle?: any;
@@ -66,7 +67,13 @@ const Modal = ({
{!noHeader && (
{!!title && {title}}
- {onClose && }
+ {onClose && (
+
+ )}
)}
diff --git a/wondrous-bot-admin/src/graphql/fragments/orgAsset.ts b/wondrous-bot-admin/src/graphql/fragments/orgAsset.ts
new file mode 100644
index 0000000000..9f6a46a01f
--- /dev/null
+++ b/wondrous-bot-admin/src/graphql/fragments/orgAsset.ts
@@ -0,0 +1,14 @@
+import { gql } from "@apollo/client";
+
+export const OrgAssetFragment = gql`
+ fragment OrgAssetFragment on OrgAsset {
+ id
+ orgId
+ purpose
+ mediaType
+ slug
+ publicUrl
+ cdnUrl
+ removedAt
+ }
+`;
diff --git a/wondrous-bot-admin/src/graphql/mutations/orgAsset.ts b/wondrous-bot-admin/src/graphql/mutations/orgAsset.ts
new file mode 100644
index 0000000000..964a900b4e
--- /dev/null
+++ b/wondrous-bot-admin/src/graphql/mutations/orgAsset.ts
@@ -0,0 +1,18 @@
+import { gql } from "@apollo/client";
+
+export const UPSERT_ORG_CUSTOM_BANNER = gql`
+ mutation upsertOrgCustomAsset($input: OrgAssetInput!) {
+ upsertOrgCustomAsset(input: $input) {
+ id
+ orgId
+ }
+ }
+`;
+
+export const DELETE_ORG_BANNER = gql`
+ mutation deleteOrgCustomAsset($orgAssetId: ID!) {
+ deleteOrgCustomAsset(orgAssetId: $orgAssetId) {
+ success
+ }
+ }
+`;
diff --git a/wondrous-bot-admin/src/graphql/queries/orgAsset.ts b/wondrous-bot-admin/src/graphql/queries/orgAsset.ts
new file mode 100644
index 0000000000..437c9c2c29
--- /dev/null
+++ b/wondrous-bot-admin/src/graphql/queries/orgAsset.ts
@@ -0,0 +1,11 @@
+import { gql } from "@apollo/client";
+import { OrgAssetFragment } from "graphql/fragments/orgAsset";
+
+export const GET_ORG_CUSTOM_ASSETS = gql`
+ query getOrgCustomAssets($orgId: ID!) {
+ getOrgCustomAssets(orgId: $orgId) {
+ ...OrgAssetFragment
+ }
+ }
+ ${OrgAssetFragment}
+`;
diff --git a/wondrous-bot-admin/src/pages/settings/customize-banners.tsx b/wondrous-bot-admin/src/pages/settings/customize-banners.tsx
new file mode 100644
index 0000000000..77a5a54402
--- /dev/null
+++ b/wondrous-bot-admin/src/pages/settings/customize-banners.tsx
@@ -0,0 +1,14 @@
+import CustomizeBanners from "components/Settings/CustomizeBanners";
+import SettingsLayout from "components/Shared/SettingsLayout";
+
+const SettingsPage = () => {
+ return (
+ <>
+
+
+
+ >
+ );
+};
+
+export default SettingsPage;
diff --git a/wondrous-bot-admin/src/types/assets.tsx b/wondrous-bot-admin/src/types/assets.tsx
index ce0e33eda1..94b037f100 100644
--- a/wondrous-bot-admin/src/types/assets.tsx
+++ b/wondrous-bot-admin/src/types/assets.tsx
@@ -1 +1 @@
-export type AvatarEditorTypes = 'HEADER_IMAGE' | 'ICON_IMAGE';
+export type AvatarEditorTypes = "HEADER_IMAGE" | "ICON_IMAGE" | "BANNER_IMAGE" | "BANNER_LOGO_IMAGE";