diff --git a/src/components/VerificationDetails.tsx b/src/components/VerificationDetails.tsx
new file mode 100644
index 0000000..c68795c
--- /dev/null
+++ b/src/components/VerificationDetails.tsx
@@ -0,0 +1,62 @@
+import React from "react";
+import moment from "moment";
+
+export type verifiedType = {
+ resultURL: string;
+ icon: string;
+ description: string;
+ type: string;
+ vendorName: string;
+ verifiedOn: string;
+ verificationExpires: string;
+};
+
+export type VerificationDetailsProps = {
+ verification: {
+ icon: string;
+ verified: verifiedType[];
+ };
+};
+
+const VerificationDetails = ({ verification }: VerificationDetailsProps) => {
+ return (
+
+ {verification?.verified &&
+ verification?.verified.map((item, index) => (
+ <>
+
+
+ Verified By {item.vendorName}
+ {" "}
+
{item?.description}
+
+ View Report
+
+
+
+
+
+ Verified On {moment(item?.verifiedOn).format("DD/MM/YYYY")}
+ {" "}
+
+
+
+ Expires On{" "}
+ {moment(item?.verificationExpires).format("DD/MM/YYYY")}
+ {" "}
+
+
+ {index !== verification?.verified.length - 1 && (
+
+ )}
+ >
+ ))}
+
+ );
+};
+
+export default VerificationDetails;
diff --git a/src/components/app_list.tsx b/src/components/app_list.tsx
index 50512df..de36b62 100644
--- a/src/components/app_list.tsx
+++ b/src/components/app_list.tsx
@@ -6,6 +6,7 @@ import { Dapp } from "../features/dapp/models/dapp";
import { spaceMono } from "../theme";
import { Card, RImage as Image, Text } from "./index";
import { Row } from "./layout/flex";
+import { convertUrl } from "../utils";
//tags on top of app card
export function Tag(props: { children: ReactNode }) {
@@ -27,12 +28,19 @@ export function AppList(props) {
{(props.data?.length ?? false) ? props.data.map((app: Dapp) =>
{/* */}
-
+
{app.tags?.slice(0, 3).map((e) => {e} )}
- {app.name}
+ {app.name} {app?.verification && app?.verification?.icon && (
+
+ )}
{app.description.substring(0, app.description.length > 220 ? 220 : app.description.length)}
{/* */}
) : Oh No! We didnt find any dApps
}
diff --git a/src/components/card/index.tsx b/src/components/card/index.tsx
index 19e9d19..f3a029c 100644
--- a/src/components/card/index.tsx
+++ b/src/components/card/index.tsx
@@ -2,6 +2,7 @@ import Image from "next/image";
import { StarRating } from "../../pages/dapp";
import { Tag } from "../app_list";
import { Row } from "../layout/flex";
+import { convertUrl } from '../../utils'
export const Card = (props) => {
return (
@@ -29,11 +30,19 @@ export function FeaturedCard(props) {
-
+
-
+
{app.name}
+ {app?.verification && app?.verification?.icon && (
+
+ )}
{app.tags?.length ? (
diff --git a/src/features/dapp/dapp_api.ts b/src/features/dapp/dapp_api.ts
index 14c29ee..bbf4eeb 100644
--- a/src/features/dapp/dapp_api.ts
+++ b/src/features/dapp/dapp_api.ts
@@ -104,7 +104,8 @@ export class DappDataSource implements IDappDataSource {
if (currentCache.response === undefined) {
currentCache.response = newItems.response;
} else {
- currentCache.response?.push(...newItems.response);
+ currentCache.response = newItems.response;
+ // currentCache.response?.push(...newItems.response);
}
currentCache.page = newItems.page;
console.log("currentCache", currentCache);
diff --git a/src/features/dapp/models/dapp.tsx b/src/features/dapp/models/dapp.tsx
index cfc2967..c5cf23c 100644
--- a/src/features/dapp/models/dapp.tsx
+++ b/src/features/dapp/models/dapp.tsx
@@ -1,3 +1,4 @@
+import { verifiedType } from '../../../components/VerificationDetails'
export interface Dapp {
name: string;
description: string;
@@ -33,5 +34,6 @@ export interface Dapp {
rating: number;
};
users: [];
+ verification: { icon: string, verified: verifiedType[] }
minted?: boolean;
}
diff --git a/src/pages/constants.tsx b/src/pages/constants.tsx
index 51b7498..206d961 100644
--- a/src/pages/constants.tsx
+++ b/src/pages/constants.tsx
@@ -21,7 +21,7 @@ const AppStrings = {
ratings: "Ratings",
allChains: "All Chains",
anonymousAnalyticsTag: 'anonymous_odde',
-
+ verification: "Verification",
}
const allChains: {
diff --git a/src/pages/dapp/index.tsx b/src/pages/dapp/index.tsx
index 6274ba2..3ce5475 100644
--- a/src/pages/dapp/index.tsx
+++ b/src/pages/dapp/index.tsx
@@ -8,758 +8,794 @@ import { useSelector } from "react-redux";
import { useAccount } from "wagmi";
import { BASE_URL, HOST_URL } from "../../api/constants";
import {
- Button,
- ClaimButton,
- ExpandAbleText,
- RImage as Image,
- PageLayout,
+ Button,
+ ClaimButton,
+ ExpandAbleText,
+ RImage as Image,
+ PageLayout,
} from "../../components";
import { ReviewCard } from "../../components/card";
import { Column, Row } from "../../components/layout/flex";
import { getApp } from "../../features/app/app_slice";
import { merokuToCustomCategory } from "../../features/categories";
import {
- useGetAppRatingQuery,
- useGetBuildDownloadUrlQuery,
- useGetDappByOwnerAddressQuery,
- usePostReviewMutation,
+ useGetAppRatingQuery,
+ useGetBuildDownloadUrlQuery,
+ useGetDappByOwnerAddressQuery,
+ usePostReviewMutation,
} from "../../features/dapp/dapp_api";
import { Dapp } from "../../features/dapp/models/dapp";
import { Review } from "../../features/dapp/models/review";
import { useSearchByIdQuery } from "../../features/search";
import { AppStrings } from "../constants";
+import { convertUrl } from "../../utils";
+import VerificationDetails from "../../components/VerificationDetails";
Modal.setAppElement("#__next");
// dapp page, shows complete dapp info
const modalStyles = {
- overlay: {
- background: "rgba(0,0,0,0.80)",
- },
- content: {
- padding: 0,
- top: "80px",
- border: 0,
- background: "transparent",
- },
+ overlay: {
+ background: "rgba(0,0,0,0.80)",
+ },
+ content: {
+ padding: 0,
+ top: "80px",
+ border: 0,
+ background: "transparent",
+ },
};
const reviewModalStyle = {
- overlay: {
- background: "rgba(0,0,0,0.7)",
- },
- content: {
- padding: "24px",
- top: "calc(50% - (30vw / 2))",
- border: 0,
- width: "512px",
- height: "512px",
- margin: "0 auto",
- background: "#141318",
- borderRadius: "16px",
- },
+ overlay: {
+ background: "rgba(0,0,0,0.7)",
+ },
+ content: {
+ padding: "24px",
+ top: "calc(50% - (30vw / 2))",
+ border: 0,
+ width: "512px",
+ height: "512px",
+ margin: "0 auto",
+ background: "#141318",
+ borderRadius: "16px",
+ },
};
function Divider(props) {
- return
;
+ return
;
}
function SocialButton(props) {
- return (
-
- );
+ return (
+
+ );
}
function DappDetailSection(props) {
- return (
-
- {props.title && (
-
- {props.title}
-
- )}
- {props.children}
-
- );
+ return (
+
+ {props.title && (
+
+ {props.title}
+
+ )}
+ {props.children}
+
+ );
}
//this button redirects to analytics url which redirects to download url if wallet is connected otherwise it calls getBuildUrl and then redirects to build url.
function DownloadButton(props) {
- const { href, dApp } = props;
- const { data, isLoading, isFetching } = useGetBuildDownloadUrlQuery(dApp.dappId)
- if (isLoading || isFetching) return null;
- console.log(dApp.dappId)
- console.log(href)
- console.log(data, isLoading, isFetching);
- const downloadAvailable = dApp.availableOnPlatform.includes('android') || dApp.availableOnPlatform.includes('ios');
- const classnames = classNames({
- 'text-[#ddd]': !downloadAvailable,
- 'text-[#fff]': downloadAvailable,
- 'p-3 font-[600] text-[14px]': true,
- });
- const currentColor = downloadAvailable && (href != undefined || data != undefined) ? "#fff" : "#525059";
- return
-
-
-
- ;
+ const { href, dApp } = props;
+ const { data, isLoading, isFetching } = useGetBuildDownloadUrlQuery(
+ dApp.dappId
+ );
+ if (isLoading || isFetching) return null;
+ console.log(dApp.dappId);
+ console.log(href);
+ console.log(data, isLoading, isFetching);
+ const downloadAvailable =
+ dApp.availableOnPlatform.includes("android") ||
+ dApp.availableOnPlatform.includes("ios");
+ const classnames = classNames({
+ "text-[#ddd]": !downloadAvailable,
+ "text-[#fff]": downloadAvailable,
+ "p-3 font-[600] text-[14px]": true,
+ });
+ const currentColor =
+ downloadAvailable && (href != undefined || data != undefined)
+ ? "#fff"
+ : "#525059";
+ return (
+
+
+
+
+
+ );
}
//Claiming a dapp on meroku .
function ClaimDappSection(props) {
- const { onClick, address, onOpenConnectModal, minted } = props;
- return (
-
-
-
- Claim this dApp
-
-
- This dApp has not been claimed by its developers. Click here
- to open the Meroku platform and claim your .app domain
-
- {/* {!address && onOpenConnectModal &&
Do you own this dApp? Connect wallet to update
} */}
-
- Claim
-
- );
+ const { onClick, address, onOpenConnectModal, minted } = props;
+ return (
+
+
+
+ Claim this dApp
+
+
+ This dApp has not been claimed by its developers. Click here to open
+ the Meroku platform and claim your .app domain
+
+ {/* {!address && onOpenConnectModal &&
Do you own this dApp? Connect wallet to update
} */}
+
+ Claim
+
+ );
}
// if the user is owner of the dapp, it shows update dapp button.
function UpdateDappSection(props) {
- const { onClick } = props;
- return (
-
-
-
- Update dApp
-
-
- Click here to update the dApp metadata on the Meroku
- platform. You are seeing this because you have claimed this
- dApp's .app namespace
-
-
- Update
-
- );
+ const { onClick } = props;
+ return (
+
+
+
Update dApp
+
+ Click here to update the dApp metadata on the Meroku platform. You are
+ seeing this because you have claimed this dApp's .app namespace
+
+
+ Update
+
+ );
}
function Input(props) {
- return (
-
- );
+ return (
+
+ );
}
export function StarRating(props) {
- const { editable, onChange } = props;
- const [rating, setRating] = useState(props.rating);
- const [hover, setHover] = useState(0);
- useEffect(() => {
- if (typeof onChange === "function") {
- onChange(rating);
- }
- }, [rating]);
- return (
- setRating(rating) : undefined}
- >
- {[...Array(5)].map((_, idx) => {
- idx += 1;
- return (
- setRating(idx) : undefined}
- onMouseEnter={
- editable ? () => setHover(idx) : undefined
- }
- onMouseLeave={
- editable ? () => setRating(rating) : undefined
- }
- className={`icon ${idx <= (rating || hover) ? "icon-filled" : null
- }`}
- width="24"
- height="25"
- viewBox="0 0 24 25"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
-
-
- );
- })}
-
- );
+ const { editable, onChange } = props;
+ const [rating, setRating] = useState(props.rating);
+ const [hover, setHover] = useState(0);
+ useEffect(() => {
+ if (typeof onChange === "function") {
+ onChange(rating);
+ }
+ }, [rating]);
+ return (
+ setRating(rating) : undefined}
+ >
+ {[...Array(5)].map((_, idx) => {
+ idx += 1;
+ return (
+ setRating(idx) : undefined}
+ onMouseEnter={editable ? () => setHover(idx) : undefined}
+ onMouseLeave={editable ? () => setRating(rating) : undefined}
+ className={`icon ${
+ idx <= (rating || hover) ? "icon-filled" : null
+ }`}
+ width="24"
+ height="25"
+ viewBox="0 0 24 25"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+
+
+ );
+ })}
+
+ );
}
// review is only possible when user has either opened or downloaded dapp via store after connecting wallet.
function ReviewDialog(props) {
- const [postReview, result, isLoading, isFetching] = usePostReviewMutation();
- const [errors, setErrors] = useState();
- const { address } = useAccount();
- const [review, setReview] = useState({
- dappId: props.dappId,
- userAddress: address,
- } as Review);
- const onSubmit = (evt) => {
- console.log(result.isUpdating);
-
- postReview({ ...review, rating: review.rating ?? 0 })
- .unwrap()
- .then((_) => {
- props.onRequestClose();
- })
- .catch((err) => {
- console.log(err);
- setErrors(err);
- });
- console.log(result.isUpdating);
- };
-
- if (errors) {
- return (
-
-
- Failed to add review
-
- props.onRequestClose()}
- className="absolute right-0 "
- >
-
-
-
-
-
- Have you opened or downloaded dapp before posting review?
-
-
- );
- }
- return (
- <>
-
-
- Add Review
-
- props.onRequestClose()}
- className="absolute right-0 "
- >
-
-
-
-
-
- Add Rating
-
- setReview({ ...review, rating: val })
- }
- />
-
-
- Write a review
-
- setReview({ ...review, comment: evt.target.value })
- }
- />
-
-
-
- Submit
-
-
- >
- );
+ const [postReview, result, isLoading, isFetching] = usePostReviewMutation();
+ const [errors, setErrors] = useState();
+ const { address } = useAccount();
+ const [review, setReview] = useState({
+ dappId: props.dappId,
+ userAddress: address,
+ } as Review);
+ const onSubmit = (evt) => {
+ console.log(result.isUpdating);
+
+ postReview({ ...review, rating: review.rating ?? 0 })
+ .unwrap()
+ .then((_) => {
+ props.onRequestClose();
+ })
+ .catch((err) => {
+ console.log(err);
+ setErrors(err);
+ });
+ console.log(result.isUpdating);
+ };
+
+ if (errors) {
+ return (
+
+
+ Failed to add review
+
+ props.onRequestClose()}
+ className="absolute right-0 "
+ >
+
+
+
+
+
+ Have you opened or downloaded dapp before posting review?
+
+
+ );
+ }
+ return (
+ <>
+
+ Add Review
+ props.onRequestClose()}
+ className="absolute right-0 "
+ >
+
+
+
+
+
+ Add Rating
+ setReview({ ...review, rating: val })}
+ />
+
+
+ Write a review
+
+ setReview({ ...review, comment: evt.target.value })
+ }
+ />
+
+
+
+ Submit
+
+
+ >
+ );
}
function AppRatingList(props) {
- const { data, isLoading, isFetching } = useGetAppRatingQuery(props.id);
- const { openConnectModal } = useConnectModal();
- const dApp = props.dapp;
-
- const { address } = useAccount();
- if (isLoading || isFetching) return null;
- return (
- <>
-
-
- {AppStrings.reviewsTitle}
-
- {
- if (address) {
- props.onCreateReivew();
- return;
- } else if (openConnectModal) {
- openConnectModal();
- }
- }}
- >
-
-
-
-
-
-
-
-
-
- Add review
-
-
-
-
-
- {Math.round((dApp?.metrics?.rating ?? 0) * 10) / 10}
-
-
-
-
- {dApp?.metrics?.ratingsCount ?? 0} Ratings
-
-
- {data.data.slice(0, 2).map((review) => (
-
- ))}
-
- {!!data.data.length && (
-
-
- View More
-
-
- )}
-
- >
- );
+ const { data, isLoading, isFetching } = useGetAppRatingQuery(props.id);
+ const { openConnectModal } = useConnectModal();
+ const dApp = props.dapp;
+
+ const { address } = useAccount();
+ if (isLoading || isFetching) return null;
+ return (
+ <>
+
+
+ {AppStrings.reviewsTitle}
+
+ {
+ if (address) {
+ props.onCreateReivew();
+ return;
+ } else if (openConnectModal) {
+ openConnectModal();
+ }
+ }}
+ >
+
+
+
+
+
+
+
+
+
+ Add review
+
+
+
+
+
+ {Math.round((dApp?.metrics?.rating ?? 0) * 10) / 10}
+
+
+
+
+ {dApp?.metrics?.ratingsCount ?? 0} Ratings
+
+
+ {data.data.slice(0, 2).map((review) => (
+
+ ))}
+
+ {!!data.data.length && (
+
+
+ View More
+
+
+ )}
+
+ >
+ );
}
function DappList(props) {
- const router = useRouter();
- const [isClaimOpen, setClaimOpen] = useState(false);
- const { openConnectModal } = useConnectModal();
- const app = useSelector(getApp);
- const { query } = useRouter();
- const [isReviewModalOpen, setIsReviewModalOpen] = useState(false);
- useEffect(() => {
- if (isClaimOpen) {
- document.body.style.overflow = "hidden";
- } else {
- document.body.style.overflow = "unset";
- }
- }, [isClaimOpen, isReviewModalOpen]);
-
- const { data, isFetching, isLoading } = useSearchByIdQuery(
- query.id,
- {
- page: 1,
- limit: 1,
- chainId: app.chainId,
- },
- {
- refetchOnMountOrArgChange: false,
- }
- );
-
- const { address } = useAccount();
-
- const { ownedApps, isOwnedAppsLoading } = useGetDappByOwnerAddressQuery(
- address,
- {
- skip:
- address === undefined &&
- (isLoading || isFetching || !data[0]?.minted),
- }
- );
-
- if (isLoading || isFetching)
- return (
-
-
-
-
-
-
- );
-
- if (!data) return Missing post! ;
-
- const dApp: Dapp = data.data[0];
-
- if (isLoading || isFetching)
- return (
-
-
-
-
-
-
- );
-
- if (!dApp) {
- return Missing post! ;
- }
-
- const history = JSON.parse(localStorage.getItem("dApps") ?? "{}");
- localStorage.setItem(
- "dApps",
- JSON.stringify(Object.assign({}, history, { [dApp.dappId]: dApp }))
- );
- const args = new URLSearchParams();
- let viewLink;
- let downloadLink;
- if (address) {
- args.set("userAddress", address);
- viewLink = `${BASE_URL}/o/view/${dApp.dappId}?${args.toString()}`;
- downloadLink = `${BASE_URL}/o/download/${dApp.dappId
- }?${args.toString()}`;
- } else {
- viewLink = dApp.appUrl;
- }
-
- const isOwner = isOwnedAppsLoading
- ? false
- : ownedApps?.data?.includes(dApp.dappId) || false;
- const customCategory: string = merokuToCustomCategory(
- dApp?.category,
- dApp?.subCategory
- ).category as string;
-
- const getIframeSrc = (): string => {
- return isOwner
- ? "https://app.meroku.org/update"
- : "https://app.meroku.org/app";
- };
-
- const onClaimButtonClick = () => {
- if (!!address) {
- setClaimOpen(true);
- return;
- } else if (openConnectModal) {
- openConnectModal();
- }
- };
-
- return (
-
-
-
-
-
-
-
{AppStrings.allDapps}
-
- {dApp.images.banner && (
-
-
-
- )}
-
+
+ {isReviewModalOpen && (
+ setIsReviewModalOpen(false)}
+ >
+ setIsReviewModalOpen(false)}
+ />
+
+ )}
+ {isClaimOpen && (
+ setClaimOpen(false)}
+ style={modalStyles}
+ >
+
+
+
setClaimOpen(false)}>
+
+
+
+
+
+
+
+
+
+
+ )}
+
+ );
}
export default DappList;
diff --git a/src/utils.ts b/src/utils.ts
new file mode 100644
index 0000000..cda19bf
--- /dev/null
+++ b/src/utils.ts
@@ -0,0 +1,12 @@
+export const convertUrl = (url: string) => {
+ if(url.includes('.ipfs.thirdwebstorage.com')){
+ let newUrl = url.replace('.ipfs.thirdwebstorage.com', '')
+ newUrl = newUrl.replace('https://', '')
+ return 'https://ipfs.io/ipfs/' + newUrl;
+ }
+ if(url.includes('https://ipfs-2.thirdwebcdn.com/ipfs/')){
+ const newUrl = url.replace('https://ipfs-2.thirdwebcdn.com/ipfs/', 'https://ipfs.io/ipfs/')
+ return newUrl;
+ }
+ return url;
+};
\ No newline at end of file