wip: remove metamask app (#4049)
* wip: disable metamask app * fix: remove dont comment * fix: remove dont comment * Update packages/app-store/index.ts Co-authored-by: Peer Richelsen <peeroke@gmail.com> * Update packages/app-store/index.ts Co-authored-by: Peer Richelsen <peeroke@gmail.com> * fix: bookingpage * fix: remove web3Details zod * removed unused web3 * Build fixes Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Peer Richelsen <peer@cal.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: zomars <zomars@me.com>
This commit is contained in:
parent
015ed6d4f9
commit
1948455be0
|
@ -15,7 +15,6 @@ import {
|
|||
useIsBackgroundTransparent,
|
||||
useIsEmbed,
|
||||
} from "@calcom/embed-core/embed-iframe";
|
||||
import { useContracts } from "@calcom/features/ee/web3/contexts/contractsContext";
|
||||
import CustomBranding from "@calcom/lib/CustomBranding";
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||
|
@ -292,7 +291,6 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||
const { rescheduleUid } = query;
|
||||
useTheme(profile.theme);
|
||||
const { t } = useLocale();
|
||||
const { contracts } = useContracts();
|
||||
const availabilityDatePickerEmbedStyles = useEmbedStyles("availabilityDatePicker");
|
||||
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
|
||||
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
|
||||
|
@ -313,15 +311,6 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||
// TODO: Improve this;
|
||||
useExposePlanGlobally(eventType.users.length === 1 ? eventType.users[0].plan : "PRO");
|
||||
|
||||
// TODO: this needs to be extracted elsewhere
|
||||
useEffect(() => {
|
||||
if (eventType.metadata.smartContractAddress) {
|
||||
const eventOwner = eventType.users[0];
|
||||
if (!contracts[(eventType.metadata.smartContractAddress || null) as number])
|
||||
router.replace(`/${eventOwner.username}`);
|
||||
}
|
||||
}, [contracts, eventType.metadata.smartContractAddress, eventType.users, router]);
|
||||
|
||||
const [recurringEventCount, setRecurringEventCount] = useState(eventType.recurringEvent?.count);
|
||||
|
||||
const telemetry = useTelemetry();
|
||||
|
|
|
@ -27,7 +27,6 @@ import {
|
|||
useIsBackgroundTransparent,
|
||||
useIsEmbed,
|
||||
} from "@calcom/embed-core/embed-iframe";
|
||||
import { useContracts } from "@calcom/features/ee/web3/contexts/contractsContext";
|
||||
import CustomBranding from "@calcom/lib/CustomBranding";
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
|
@ -96,7 +95,6 @@ const BookingPage = ({
|
|||
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
|
||||
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
|
||||
const router = useRouter();
|
||||
const { contracts } = useContracts();
|
||||
const { data: session } = useSession();
|
||||
const isBackgroundTransparent = useIsBackgroundTransparent();
|
||||
const telemetry = useTelemetry();
|
||||
|
@ -112,15 +110,6 @@ const BookingPage = ({
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (eventType.metadata.smartContractAddress) {
|
||||
const eventOwner = eventType.users[0];
|
||||
|
||||
if (!contracts[(eventType.metadata.smartContractAddress || null) as number])
|
||||
router.replace(`/${eventOwner.username}`);
|
||||
}
|
||||
}, [contracts, eventType.metadata.smartContractAddress, eventType.users, router]);
|
||||
|
||||
const mutation = useMutation(createBooking, {
|
||||
onSuccess: async (responseData) => {
|
||||
const { id, attendees, paymentUid } = responseData;
|
||||
|
@ -192,9 +181,6 @@ const BookingPage = ({
|
|||
const date = asStringOrNull(router.query.date);
|
||||
|
||||
const [guestToggle, setGuestToggle] = useState(booking && booking.attendees.length > 1);
|
||||
|
||||
const eventTypeDetail = { isWeb3Active: false, ...eventType };
|
||||
|
||||
// it would be nice if Prisma at some point in the future allowed for Json<Location>; as of now this is not the case.
|
||||
const locations: LocationObject[] = useMemo(
|
||||
() => (eventType.locations as LocationObject[]) || [],
|
||||
|
@ -344,20 +330,11 @@ const BookingPage = ({
|
|||
{}
|
||||
);
|
||||
|
||||
let web3Details: Record<"userWallet" | "userSignature", string> | undefined;
|
||||
if (eventTypeDetail.metadata.smartContractAddress) {
|
||||
web3Details = {
|
||||
userWallet: window.web3.currentProvider.selectedAddress,
|
||||
userSignature: contracts[(eventTypeDetail.metadata.smartContractAddress || null) as number],
|
||||
};
|
||||
}
|
||||
|
||||
if (recurringDates.length) {
|
||||
// Identify set of bookings to one intance of recurring event to support batch changes
|
||||
const recurringEventId = uuidv4();
|
||||
const recurringBookings = recurringDates.map((recurringDate) => ({
|
||||
...booking,
|
||||
web3Details,
|
||||
start: dayjs(recurringDate).format(),
|
||||
end: dayjs(recurringDate).add(eventType.length, "minute").format(),
|
||||
eventTypeId: eventType.id,
|
||||
|
@ -387,7 +364,6 @@ const BookingPage = ({
|
|||
} else {
|
||||
mutation.mutate({
|
||||
...booking,
|
||||
web3Details,
|
||||
start: dayjs(date).format(),
|
||||
end: dayjs(date).add(eventType.length, "minute").format(),
|
||||
eventTypeId: eventType.id,
|
||||
|
@ -549,11 +525,6 @@ const BookingPage = ({
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
{eventTypeDetail.isWeb3Active && eventType.metadata.smartContractAddress && (
|
||||
<p className="text-bookinglight mb-1 -ml-2 px-2">
|
||||
{t("requires_ownership_of_a_token") + " " + eventType.metadata.smartContractAddress}
|
||||
</p>
|
||||
)}
|
||||
{booking?.startTime && rescheduleUid && (
|
||||
<div>
|
||||
<p className="mt-8 mb-2 text-sm " data-testid="former_time_p">
|
||||
|
|
|
@ -9,7 +9,6 @@ import { ComponentProps, ReactNode } from "react";
|
|||
|
||||
import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/providerDynamic";
|
||||
import DynamicIntercomProvider from "@calcom/features/ee/support/lib/intercom/providerDynamic";
|
||||
import { ContractsProvider } from "@calcom/features/ee/web3/contexts/contractsContext";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { MetaProvider } from "@calcom/ui/v2/core/Meta";
|
||||
|
||||
|
@ -71,22 +70,20 @@ const AppProviders = (props: AppPropsWithChildren) => {
|
|||
|
||||
const RemainingProviders = (
|
||||
<EventCollectionProvider options={{ apiPath: "/api/collect-events" }}>
|
||||
<ContractsProvider>
|
||||
<SessionProvider session={session || undefined}>
|
||||
<CustomI18nextProvider {...props}>
|
||||
<TooltipProvider>
|
||||
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
|
||||
<ThemeProvider
|
||||
enableColorScheme={false}
|
||||
storageKey={storageKey}
|
||||
forcedTheme={forcedTheme}
|
||||
attribute="class">
|
||||
<MetaProvider>{props.children}</MetaProvider>
|
||||
</ThemeProvider>
|
||||
</TooltipProvider>
|
||||
</CustomI18nextProvider>
|
||||
</SessionProvider>
|
||||
</ContractsProvider>
|
||||
<SessionProvider session={session || undefined}>
|
||||
<CustomI18nextProvider {...props}>
|
||||
<TooltipProvider>
|
||||
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
|
||||
<ThemeProvider
|
||||
enableColorScheme={false}
|
||||
storageKey={storageKey}
|
||||
forcedTheme={forcedTheme}
|
||||
attribute="class">
|
||||
<MetaProvider>{props.children}</MetaProvider>
|
||||
</ThemeProvider>
|
||||
</TooltipProvider>
|
||||
</CustomI18nextProvider>
|
||||
</SessionProvider>
|
||||
</EventCollectionProvider>
|
||||
);
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
"@heroicons/react": "^1.0.6",
|
||||
"@hookform/error-message": "^2.0.0",
|
||||
"@hookform/resolvers": "^2.9.7",
|
||||
"@metamask/providers": "^8.1.1",
|
||||
"@next-auth/prisma-adapter": "^1.0.4",
|
||||
"@next/bundle-analyzer": "12.1.6",
|
||||
"@radix-ui/react-avatar": "^0.1.4",
|
||||
|
|
|
@ -14,7 +14,6 @@ import {
|
|||
useEmbedStyles,
|
||||
useIsEmbed,
|
||||
} from "@calcom/embed-core/embed-iframe";
|
||||
import type { CryptoSectionProps } from "@calcom/features/ee/web3/components/CryptoSection";
|
||||
import CustomBranding from "@calcom/lib/CustomBranding";
|
||||
import defaultEvents, {
|
||||
getDynamicEventDescription,
|
||||
|
@ -39,14 +38,6 @@ import { ssrInit } from "@server/lib/ssr";
|
|||
|
||||
const EventTypeDescription = dynamic(() => import("@calcom/ui/v2/modules/event-types/EventTypeDescription"));
|
||||
const HeadSeo = dynamic(() => import("@components/seo/head-seo"));
|
||||
const CryptoSection = dynamic<CryptoSectionProps>(
|
||||
() => import("@calcom/features/ee/web3/components/CryptoSection")
|
||||
);
|
||||
|
||||
interface EvtsToVerify {
|
||||
[evtId: string]: boolean;
|
||||
}
|
||||
|
||||
export default function User(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { users, profile, eventTypes, isDynamicGroup, dynamicNames, dynamicUsernames, isSingleUser } = props;
|
||||
const [user] = users; //To be used when we only have a single user, not dynamic group
|
||||
|
@ -103,7 +94,6 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
delete query.user; // So it doesn't display in the Link (and make tests fail)
|
||||
useExposePlanGlobally("PRO");
|
||||
const nameOrUsername = user.name || user.username || "";
|
||||
const [evtsToVerify, setEvtsToVerify] = useState<EvtsToVerify>({});
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -181,20 +171,10 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
query,
|
||||
}}>
|
||||
<a
|
||||
onClick={async (e) => {
|
||||
// If a token is required for this event type, add a click listener that checks whether the user verified their wallet or not
|
||||
if (type.metadata.smartContractAddress && !evtsToVerify[type.id]) {
|
||||
const showToast = (await import("@calcom/lib/notification")).default;
|
||||
e.preventDefault();
|
||||
showToast(
|
||||
"You must verify a wallet with a token belonging to the specified smart contract first",
|
||||
"error"
|
||||
);
|
||||
} else {
|
||||
sdkActionManager?.fire("eventTypeSelected", {
|
||||
eventType: type,
|
||||
});
|
||||
}
|
||||
onClick={async () => {
|
||||
sdkActionManager?.fire("eventTypeSelected", {
|
||||
eventType: type,
|
||||
});
|
||||
}}
|
||||
className="block w-full p-5"
|
||||
data-testid="event-type-link">
|
||||
|
@ -207,16 +187,6 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
<EventTypeDescription eventType={type} />
|
||||
</a>
|
||||
</Link>
|
||||
{type.isWeb3Active && type.metadata.smartContractAddress && (
|
||||
<CryptoSection
|
||||
id={type.id}
|
||||
pathname={`/${user.username}/${type.slug}`}
|
||||
smartContractAddress={type.metadata.smartContractAddress as string}
|
||||
verified={evtsToVerify[type.id]}
|
||||
setEvtsToVerify={setEvtsToVerify}
|
||||
oneStep
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
|
@ -340,21 +310,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
brandColor: user.brandColor,
|
||||
darkBrandColor: user.darkBrandColor,
|
||||
};
|
||||
const usersIds = users.map((user) => user.id);
|
||||
const credentials = await prisma.credential.findMany({
|
||||
where: {
|
||||
userId: {
|
||||
in: usersIds,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
type: true,
|
||||
key: true,
|
||||
},
|
||||
});
|
||||
|
||||
const web3Credentials = credentials.find((credential) => credential.type.includes("_web3"));
|
||||
|
||||
const eventTypesWithHidden = isDynamicGroup ? [] : await getEventTypesWithHiddenFromDB(user.id, user.plan);
|
||||
const dataFetchEnd = Date.now();
|
||||
|
@ -366,10 +321,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
const eventTypes = eventTypesRaw.map((eventType) => ({
|
||||
...eventType,
|
||||
metadata: (eventType.metadata || {}) as JSONObject,
|
||||
isWeb3Active:
|
||||
web3Credentials && web3Credentials.key
|
||||
? (((web3Credentials.key as JSONObject).isWeb3Active || false) as boolean)
|
||||
: false,
|
||||
}));
|
||||
|
||||
const isSingleUser = users.length === 1;
|
||||
|
|
|
@ -111,29 +111,10 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
|||
|
||||
if (!eventTypeRaw) return { notFound: true };
|
||||
|
||||
const credentials = await prisma.credential.findMany({
|
||||
where: {
|
||||
userId: {
|
||||
in: users.map((user) => user.id),
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
type: true,
|
||||
key: true,
|
||||
},
|
||||
});
|
||||
|
||||
const web3Credentials = credentials.find((credential) => credential.type.includes("_web3"));
|
||||
|
||||
const eventType = {
|
||||
...eventTypeRaw,
|
||||
metadata: (eventTypeRaw.metadata || {}) as JSONObject,
|
||||
recurringEvent: parseRecurringEvent(eventTypeRaw.recurringEvent),
|
||||
isWeb3Active:
|
||||
web3Credentials && web3Credentials.key
|
||||
? (((web3Credentials.key as JSONObject).isWeb3Active || false) as boolean)
|
||||
: false,
|
||||
};
|
||||
|
||||
const eventTypeObject = [eventType].map((e) => {
|
||||
|
|
|
@ -19,7 +19,6 @@ import {
|
|||
sendScheduledEmails,
|
||||
sendScheduledSeatsEmails,
|
||||
} from "@calcom/emails";
|
||||
import verifyAccount from "@calcom/features/ee/web3/utils/verifyAccount";
|
||||
import { scheduleWorkflowReminders } from "@calcom/features/ee/workflows/lib/reminders/reminderScheduler";
|
||||
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
|
||||
import { getDefaultEvent, getGroupName, getUsernameList } from "@calcom/lib/defaultEvents";
|
||||
|
@ -556,12 +555,6 @@ async function handler(req: NextApiRequest) {
|
|||
}
|
||||
|
||||
async function createBooking() {
|
||||
// @TODO: check as metadata
|
||||
if (reqBody.web3Details) {
|
||||
const { web3Details } = reqBody;
|
||||
await verifyAccount(web3Details.userSignature, web3Details.userWallet);
|
||||
}
|
||||
|
||||
if (originalRescheduledBooking) {
|
||||
evt.title = originalRescheduledBooking?.title || evt.title;
|
||||
evt.description = originalRescheduledBooking?.description || evt.additionalNotes;
|
||||
|
|
|
@ -1,23 +1,18 @@
|
|||
import Image from "next/image";
|
||||
import React from "react";
|
||||
|
||||
import { InstallAppButton } from "@calcom/app-store/components";
|
||||
import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import showToast from "@calcom/lib/notification";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import type { App } from "@calcom/types/App";
|
||||
import { Alert } from "@calcom/ui/Alert";
|
||||
import Button from "@calcom/ui/Button";
|
||||
import EmptyScreen from "@calcom/ui/EmptyScreen";
|
||||
import { Icon } from "@calcom/ui/Icon";
|
||||
import { List, ListItem, ListItemText, ListItemTitle } from "@calcom/ui/List";
|
||||
import { List } from "@calcom/ui/List";
|
||||
import Shell, { ShellSubHeading } from "@calcom/ui/Shell";
|
||||
import SkeletonLoader from "@calcom/ui/apps/SkeletonLoader";
|
||||
|
||||
import { QueryCell } from "@lib/QueryCell";
|
||||
import classNames from "@lib/classNames";
|
||||
import { HttpError } from "@lib/core/http/error";
|
||||
|
||||
import AppsShell from "@components/AppsShell";
|
||||
import { CalendarListContainer } from "@components/integrations/CalendarListContainer";
|
||||
|
@ -144,81 +139,6 @@ const IntegrationsContainer = ({ variant, className = "" }: IntegrationsContaine
|
|||
);
|
||||
};
|
||||
|
||||
function Web3Container() {
|
||||
const { t } = useLocale();
|
||||
const result = trpc.useQuery(["viewer.web3Integration"]);
|
||||
const isWeb3Active = !!result.data?.isWeb3Active;
|
||||
return (
|
||||
<>
|
||||
{isWeb3Active && (
|
||||
<>
|
||||
<ShellSubHeading title="Web3" subtitle={t("meet_people_with_the_same_tokens")} className="mt-10" />
|
||||
<div className="lg:col-span-9 lg:pb-8">
|
||||
<List>
|
||||
<ListItem className={classNames("flex-col")}>
|
||||
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-3")}>
|
||||
<Image width={40} height={40} src="/api/app-store/metamask/icon.svg" alt="Embed" />
|
||||
<div className="flex-grow truncate pl-2">
|
||||
<ListItemTitle component="h3">
|
||||
MetaMask (
|
||||
<a
|
||||
className="text-blue-500"
|
||||
target="_blank"
|
||||
href={`${WEBSITE_URL}/web3`}
|
||||
rel="noreferrer">
|
||||
Read more
|
||||
</a>
|
||||
)
|
||||
</ListItemTitle>
|
||||
<ListItemText component="p">{t("only_book_people_and_allow")}</ListItemText>
|
||||
</div>
|
||||
<Web3ConnectBtn />
|
||||
</div>
|
||||
</ListItem>
|
||||
</List>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Web3ConnectBtn() {
|
||||
const { t } = useLocale();
|
||||
const utils = trpc.useContext();
|
||||
const result = trpc.useQuery(["viewer.web3Integration"]);
|
||||
const mutation = trpc.useMutation("viewer.enableOrDisableWeb3", {
|
||||
onSuccess: async (result) => {
|
||||
const { key } = result;
|
||||
if ((key as { isWeb3Active: boolean }).isWeb3Active) {
|
||||
showToast(t("web3_metamask_added"), "success");
|
||||
} else {
|
||||
showToast(t("web3_metamask_disconnected"), "success");
|
||||
}
|
||||
utils.invalidateQueries("viewer.web3Integration");
|
||||
},
|
||||
onError: (err) => {
|
||||
if (err instanceof HttpError) {
|
||||
const message = `${err.statusCode}: ${err.message}`;
|
||||
showToast(message, "error");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Button
|
||||
loading={mutation.isLoading}
|
||||
color={result.data?.isWeb3Active ? "warn" : "secondary"}
|
||||
disabled={result.isLoading || mutation.isLoading}
|
||||
onClick={() => {
|
||||
mutation.mutateAsync({});
|
||||
}}
|
||||
data-testid="metamask">
|
||||
{result.data?.isWeb3Active ? t("remove") : t("add")}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default function IntegrationsPage() {
|
||||
const { t } = useLocale();
|
||||
const query = trpc.useQuery(["viewer.integrations", { onlyInstalled: true }]);
|
||||
|
@ -238,7 +158,6 @@ export default function IntegrationsPage() {
|
|||
<CalendarListContainer />
|
||||
<IntegrationsContainer variant="payment" className="mt-8" />
|
||||
<IntegrationsContainer variant="other" className="mt-8" />
|
||||
<Web3Container />
|
||||
</>
|
||||
) : (
|
||||
<EmptyScreen
|
||||
|
|
|
@ -68,30 +68,10 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
|||
const eventTypeRaw = hashedLink?.eventType;
|
||||
|
||||
if (!eventTypeRaw) return { notFound: true };
|
||||
|
||||
const credentials = await prisma.credential.findMany({
|
||||
where: {
|
||||
userId: {
|
||||
in: users.map((user) => user.id),
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
type: true,
|
||||
key: true,
|
||||
},
|
||||
});
|
||||
|
||||
const web3Credentials = credentials.find((credential) => credential.type.includes("_web3"));
|
||||
|
||||
const eventType = {
|
||||
...eventTypeRaw,
|
||||
metadata: (eventTypeRaw.metadata || {}) as JSONObject,
|
||||
recurringEvent: parseRecurringEvent(eventTypeRaw.recurringEvent),
|
||||
isWeb3Active:
|
||||
web3Credentials && web3Credentials.key
|
||||
? (((web3Credentials.key as JSONObject).isWeb3Active || false) as boolean)
|
||||
: false,
|
||||
};
|
||||
|
||||
const eventTypeObject = [eventType].map((e) => {
|
||||
|
|
|
@ -76,7 +76,6 @@ type OptionTypeBase = {
|
|||
export type FormValues = {
|
||||
title: string;
|
||||
eventTitle: string;
|
||||
smartContractAddress: string;
|
||||
eventName: string;
|
||||
slug: string;
|
||||
length: number;
|
||||
|
@ -559,7 +558,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||
const {
|
||||
periodDates,
|
||||
periodCountCalendarDays,
|
||||
smartContractAddress,
|
||||
giphyThankYouPage,
|
||||
beforeBufferTime,
|
||||
afterBufferTime,
|
||||
|
@ -581,7 +579,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||
afterEventBuffer: afterBufferTime,
|
||||
seatsPerTimeSlot: Number.isNaN(seatsPerTimeSlot) ? null : seatsPerTimeSlot,
|
||||
metadata: {
|
||||
...(smartContractAddress ? { smartContractAddress } : {}),
|
||||
...(giphyThankYouPage ? { giphyThankYouPage } : {}),
|
||||
},
|
||||
});
|
||||
|
@ -853,28 +850,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{eventType.isWeb3Active && (
|
||||
<div className="block items-center sm:flex">
|
||||
<div className="min-w-48 mb-4 sm:mb-0">
|
||||
<label
|
||||
htmlFor="smartContractAddress"
|
||||
className="flex text-sm font-medium text-neutral-700">
|
||||
{t("Smart Contract Address")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<div className="relative mt-1 rounded-sm">
|
||||
<input
|
||||
type="text"
|
||||
className="block w-full rounded-sm border-gray-300 text-sm "
|
||||
placeholder={t("Example: 0x71c7656ec7ab88b098defb751b7401b5f6d8976f")}
|
||||
defaultValue={(eventType.metadata.smartContractAddress || "") as string}
|
||||
{...formMethods.register("smartContractAddress")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="block items-center sm:flex">
|
||||
<div className="min-w-48 mb-4 sm:mb-0">
|
||||
<label
|
||||
|
@ -1900,17 +1875,12 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
},
|
||||
});
|
||||
|
||||
const web3Credentials = credentials.find((credential) => credential.type.includes("_web3"));
|
||||
const { locations, metadata, ...restEventType } = rawEventType;
|
||||
const eventType = {
|
||||
...restEventType,
|
||||
recurringEvent: parseRecurringEvent(restEventType.recurringEvent),
|
||||
locations: locations as unknown as LocationObject[],
|
||||
metadata: (metadata || {}) as JSONObject,
|
||||
isWeb3Active:
|
||||
web3Credentials && web3Credentials.key
|
||||
? (((web3Credentials.key as JSONObject).isWeb3Active || false) as boolean)
|
||||
: false,
|
||||
};
|
||||
|
||||
const hasGiphyIntegration = !!credentials.find((credential) => credential.type === "giphy_other");
|
||||
|
|
|
@ -38,7 +38,6 @@ import { getTranslation } from "@server/lib/i18n";
|
|||
export type FormValues = {
|
||||
title: string;
|
||||
eventTitle: string;
|
||||
smartContractAddress: string;
|
||||
eventName: string;
|
||||
slug: string;
|
||||
length: number;
|
||||
|
@ -203,7 +202,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||
const {
|
||||
periodDates,
|
||||
periodCountCalendarDays,
|
||||
smartContractAddress,
|
||||
giphyThankYouPage,
|
||||
beforeBufferTime,
|
||||
afterBufferTime,
|
||||
|
@ -225,7 +223,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||
afterEventBuffer: afterBufferTime,
|
||||
seatsPerTimeSlot,
|
||||
metadata: {
|
||||
...(smartContractAddress ? { smartContractAddress } : {}),
|
||||
...(giphyThankYouPage ? { giphyThankYouPage } : {}),
|
||||
},
|
||||
});
|
||||
|
@ -408,17 +405,12 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
},
|
||||
});
|
||||
|
||||
const web3Credentials = credentials.find((credential) => credential.type.includes("_web3"));
|
||||
const { locations, metadata, ...restEventType } = rawEventType;
|
||||
const eventType = {
|
||||
...restEventType,
|
||||
recurringEvent: parseRecurringEvent(restEventType.recurringEvent),
|
||||
locations: locations as unknown as LocationObject[],
|
||||
metadata: (metadata || {}) as JSONObject,
|
||||
isWeb3Active:
|
||||
web3Credentials && web3Credentials.key
|
||||
? (((web3Credentials.key as JSONObject).isWeb3Active || false) as boolean)
|
||||
: false,
|
||||
};
|
||||
|
||||
const hasGiphyIntegration = !!credentials.find((credential) => credential.type === "giphy_other");
|
||||
|
|
|
@ -20,7 +20,6 @@ import { metadata as hubspotothercalendar_meta } from "./hubspotothercalendar/_m
|
|||
import { metadata as huddle01video_meta } from "./huddle01video/_metadata";
|
||||
import { metadata as jitsivideo_meta } from "./jitsivideo/_metadata";
|
||||
import { metadata as larkcalendar_meta } from "./larkcalendar/_metadata";
|
||||
import { metadata as metamask_meta } from "./metamask/_metadata";
|
||||
import { metadata as office365calendar_meta } from "./office365calendar/_metadata";
|
||||
import { metadata as office365video_meta } from "./office365video/_metadata";
|
||||
import { metadata as ping_meta } from "./ping/_metadata";
|
||||
|
@ -52,7 +51,6 @@ export const appStoreMetadata = {
|
|||
huddle01video: huddle01video_meta,
|
||||
jitsivideo: jitsivideo_meta,
|
||||
larkcalendar: larkcalendar_meta,
|
||||
metamask: metamask_meta,
|
||||
office365calendar: office365calendar_meta,
|
||||
office365video: office365video_meta,
|
||||
ping: ping_meta,
|
||||
|
@ -80,7 +78,6 @@ export const InstallAppButtonMap = {
|
|||
huddle01video: dynamic(() => import("./huddle01video/components/InstallAppButton")),
|
||||
jitsivideo: dynamic(() => import("./jitsivideo/components/InstallAppButton")),
|
||||
larkcalendar: dynamic(() => import("./larkcalendar/components/InstallAppButton")),
|
||||
metamask: dynamic(() => import("./metamask/components/InstallAppButton")),
|
||||
office365calendar: dynamic(() => import("./office365calendar/components/InstallAppButton")),
|
||||
office365video: dynamic(() => import("./office365video/components/InstallAppButton")),
|
||||
riverside: dynamic(() => import("./riverside/components/InstallAppButton")),
|
||||
|
|
|
@ -17,7 +17,6 @@ export const apiHandlers = {
|
|||
huddle01video: import("./huddle01video/api"),
|
||||
jitsivideo: import("./jitsivideo/api"),
|
||||
larkcalendar: import("./larkcalendar/api"),
|
||||
metamask: import("./metamask/api"),
|
||||
office365calendar: import("./office365calendar/api"),
|
||||
office365video: import("./office365video/api"),
|
||||
ping: import("./ping/api"),
|
||||
|
|
|
@ -12,7 +12,6 @@ import * as hubspotothercalendar from "./hubspotothercalendar";
|
|||
import * as huddle01video from "./huddle01video";
|
||||
import * as jitsivideo from "./jitsivideo";
|
||||
import * as larkcalendar from "./larkcalendar";
|
||||
import * as metamask from "./metamask";
|
||||
import * as office365calendar from "./office365calendar";
|
||||
import * as office365video from "./office365video";
|
||||
import * as slackmessaging from "./slackmessaging";
|
||||
|
@ -43,7 +42,6 @@ const appStore = {
|
|||
vital,
|
||||
zoomvideo,
|
||||
wipemycalother,
|
||||
metamask,
|
||||
giphy,
|
||||
zapier,
|
||||
exchange2013calendar,
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
---
|
||||
items:
|
||||
- /api/app-store/metamask/example1.png
|
||||
- /api/app-store/metamask/example2.png
|
||||
---
|
||||
|
||||
<Slider items={items} />
|
||||
|
||||
Only book and allow bookings from people who share the same tokens, DAOs, or NFTs.
|
||||
|
||||
Send a group scheduling link that only members of a DAO or token-based community can join.
|
||||
|
||||
Share your booking link and be sure to only receive bookings from owners of your chosen tokens or coins.
|
||||
|
||||
Provide office hours for other DAO members or outsiders who want to learn more from you.
|
||||
|
||||
[Click here to learn more](https://cal.com/web3)
|
|
@ -1,26 +0,0 @@
|
|||
import type { AppMeta } from "@calcom/types/App";
|
||||
|
||||
import _package from "./package.json";
|
||||
|
||||
export const metadata = {
|
||||
name: "MetaMask",
|
||||
description: _package.description,
|
||||
installed: true,
|
||||
category: "web3",
|
||||
// If using static next public folder, can then be referenced from the base URL (/).
|
||||
imageSrc: "/api/app-store/metamask/icon.svg",
|
||||
logo: "/api/app-store/metamask/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
rating: 5,
|
||||
reviews: 69,
|
||||
slug: "metamask",
|
||||
title: "MetaMask",
|
||||
trending: true,
|
||||
type: "metamask_web3",
|
||||
url: "https://cal.com/",
|
||||
variant: "other",
|
||||
verified: true,
|
||||
email: "help@cal.com",
|
||||
} as AppMeta;
|
||||
|
||||
export default metadata;
|
|
@ -1,39 +0,0 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session?.user?.id) {
|
||||
return res.status(401).json({ message: "You must be logged in to do this" });
|
||||
}
|
||||
|
||||
const appType = "metamask_web3";
|
||||
try {
|
||||
const alreadyInstalled = await prisma.credential.findFirst({
|
||||
where: {
|
||||
type: appType,
|
||||
userId: req.session.user.id,
|
||||
},
|
||||
});
|
||||
if (alreadyInstalled) {
|
||||
throw new Error("Already installed");
|
||||
}
|
||||
const installation = await prisma.credential.create({
|
||||
data: {
|
||||
type: appType,
|
||||
key: { isWeb3Active: true },
|
||||
userId: req.session.user.id,
|
||||
appId: "metamask",
|
||||
},
|
||||
});
|
||||
if (!installation) {
|
||||
throw new Error("Unable to create user credential for metamask");
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
return res.status(500).json({ message: error.message });
|
||||
}
|
||||
return res.status(500);
|
||||
}
|
||||
return res.status(200).json({ url: "/apps/installed" });
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
export { default as add } from "./add";
|
|
@ -1,19 +0,0 @@
|
|||
import useAddAppMutation from "../../_utils/useAddAppMutation";
|
||||
import { InstallAppButtonProps } from "../../types";
|
||||
|
||||
export default function InstallAppButton(props: InstallAppButtonProps) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore TODO: deprecate App types in favor of DB slugs
|
||||
const mutation = useAddAppMutation("metamask");
|
||||
|
||||
return (
|
||||
<>
|
||||
{props.render({
|
||||
onClick() {
|
||||
mutation.mutate("");
|
||||
},
|
||||
loading: mutation.isLoading,
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
export { default as InstallAppButton } from "./InstallAppButton";
|
|
@ -1,2 +0,0 @@
|
|||
export * as api from "./api";
|
||||
export { metadata } from "./_metadata";
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"name": "@calcom/metamask",
|
||||
"version": "0.0.0",
|
||||
"main": "./index.ts",
|
||||
"description": "Only book and allow bookings from people who share the same tokens, DAOs, or NFTs.",
|
||||
"dependencies": {
|
||||
"@calcom/prisma": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@calcom/types": "*"
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 88 KiB |
Binary file not shown.
Before Width: | Height: | Size: 515 KiB |
|
@ -1,61 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns:ev="http://www.w3.org/2001/xml-events"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 318.6 318.6"
|
||||
style="enable-background:new 0 0 318.6 318.6;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#E2761B;stroke:#E2761B;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st1{fill:#E4761B;stroke:#E4761B;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st2{fill:#D7C1B3;stroke:#D7C1B3;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st3{fill:#233447;stroke:#233447;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st4{fill:#CD6116;stroke:#CD6116;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st5{fill:#E4751F;stroke:#E4751F;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st6{fill:#F6851B;stroke:#F6851B;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st7{fill:#C0AD9E;stroke:#C0AD9E;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st8{fill:#161616;stroke:#161616;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st9{fill:#763D16;stroke:#763D16;stroke-linecap:round;stroke-linejoin:round;}
|
||||
</style>
|
||||
<polygon class="st0" points="274.1,35.5 174.6,109.4 193,65.8 "/>
|
||||
<g>
|
||||
<polygon class="st1" points="44.4,35.5 143.1,110.1 125.6,65.8 "/>
|
||||
<polygon class="st1" points="238.3,206.8 211.8,247.4 268.5,263 284.8,207.7 "/>
|
||||
<polygon class="st1" points="33.9,207.7 50.1,263 106.8,247.4 80.3,206.8 "/>
|
||||
<polygon class="st1" points="103.6,138.2 87.8,162.1 144.1,164.6 142.1,104.1 "/>
|
||||
<polygon class="st1" points="214.9,138.2 175.9,103.4 174.6,164.6 230.8,162.1 "/>
|
||||
<polygon class="st1" points="106.8,247.4 140.6,230.9 111.4,208.1 "/>
|
||||
<polygon class="st1" points="177.9,230.9 211.8,247.4 207.1,208.1 "/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st2" points="211.8,247.4 177.9,230.9 180.6,253 180.3,262.3 "/>
|
||||
<polygon class="st2" points="106.8,247.4 138.3,262.3 138.1,253 140.6,230.9 "/>
|
||||
</g>
|
||||
<polygon class="st3" points="138.8,193.5 110.6,185.2 130.5,176.1 "/>
|
||||
<polygon class="st3" points="179.7,193.5 188,176.1 208,185.2 "/>
|
||||
<g>
|
||||
<polygon class="st4" points="106.8,247.4 111.6,206.8 80.3,207.7 "/>
|
||||
<polygon class="st4" points="207,206.8 211.8,247.4 238.3,207.7 "/>
|
||||
<polygon class="st4" points="230.8,162.1 174.6,164.6 179.8,193.5 188.1,176.1 208.1,185.2 "/>
|
||||
<polygon class="st4" points="110.6,185.2 130.6,176.1 138.8,193.5 144.1,164.6 87.8,162.1 "/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st5" points="87.8,162.1 111.4,208.1 110.6,185.2 "/>
|
||||
<polygon class="st5" points="208.1,185.2 207.1,208.1 230.8,162.1 "/>
|
||||
<polygon class="st5" points="144.1,164.6 138.8,193.5 145.4,227.6 146.9,182.7 "/>
|
||||
<polygon class="st5" points="174.6,164.6 171.9,182.6 173.1,227.6 179.8,193.5 "/>
|
||||
</g>
|
||||
<polygon class="st6" points="179.8,193.5 173.1,227.6 177.9,230.9 207.1,208.1 208.1,185.2 "/>
|
||||
<polygon class="st6" points="110.6,185.2 111.4,208.1 140.6,230.9 145.4,227.6 138.8,193.5 "/>
|
||||
<polygon class="st7" points="180.3,262.3 180.6,253 178.1,250.8 140.4,250.8 138.1,253 138.3,262.3 106.8,247.4 117.8,256.4
|
||||
140.1,271.9 178.4,271.9 200.8,256.4 211.8,247.4 "/>
|
||||
<polygon class="st8" points="177.9,230.9 173.1,227.6 145.4,227.6 140.6,230.9 138.1,253 140.4,250.8 178.1,250.8 180.6,253 "/>
|
||||
<g>
|
||||
<polygon class="st9" points="278.3,114.2 286.8,73.4 274.1,35.5 177.9,106.9 214.9,138.2 267.2,153.5 278.8,140 273.8,136.4
|
||||
281.8,129.1 275.6,124.3 283.6,118.2 "/>
|
||||
<polygon class="st9" points="31.8,73.4 40.3,114.2 34.9,118.2 42.9,124.3 36.8,129.1 44.8,136.4 39.8,140 51.3,153.5 103.6,138.2
|
||||
140.6,106.9 44.4,35.5 "/>
|
||||
</g>
|
||||
<polygon class="st6" points="267.2,153.5 214.9,138.2 230.8,162.1 207.1,208.1 238.3,207.7 284.8,207.7 "/>
|
||||
<polygon class="st6" points="103.6,138.2 51.3,153.5 33.9,207.7 80.3,207.7 111.4,208.1 87.8,162.1 "/>
|
||||
<polygon class="st6" points="174.6,164.6 177.9,106.9 193.1,65.8 125.6,65.8 140.6,106.9 144.1,164.6 145.3,182.8 145.4,227.6
|
||||
173.1,227.6 173.3,182.8 "/>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.9 KiB |
|
@ -1,9 +0,0 @@
|
|||
[
|
||||
{
|
||||
"inputs": [{ "internalType": "address", "name": "owner", "type": "address" }],
|
||||
"name": "balanceOf",
|
||||
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
|
@ -1,143 +0,0 @@
|
|||
import Router from "next/router";
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import Web3 from "web3";
|
||||
import type { AbstractProvider } from "web3-core";
|
||||
import { AbiItem } from "web3-utils";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import showToast from "@calcom/lib/notification";
|
||||
import { Button } from "@calcom/ui/Button";
|
||||
|
||||
import { withLicenseRequired } from "../../common/components/LicenseRequired";
|
||||
import genericAbi from "../abis/abiWithGetBalance.json";
|
||||
import { useContracts } from "../contexts/contractsContext";
|
||||
import verifyAccount, { AUTH_MESSAGE } from "../utils/verifyAccount";
|
||||
|
||||
interface Window {
|
||||
ethereum: AbstractProvider & { selectedAddress: string };
|
||||
web3: Web3;
|
||||
}
|
||||
interface EvtsToVerify {
|
||||
[eventId: string]: boolean;
|
||||
}
|
||||
|
||||
declare const window: Window;
|
||||
|
||||
export interface CryptoSectionProps {
|
||||
id: number | string;
|
||||
pathname: string;
|
||||
smartContractAddress: string;
|
||||
/** When set to true, there will be only 1 button which will both connect Metamask and verify the user's wallet. Otherwise, it will be in 2 steps with 2 buttons. */
|
||||
oneStep: boolean;
|
||||
verified: boolean | undefined;
|
||||
setEvtsToVerify: React.Dispatch<React.SetStateAction<Record<number | string, boolean>>>;
|
||||
}
|
||||
|
||||
const CryptoSection = (props: CryptoSectionProps) => {
|
||||
// Crypto section which should be shown on booking page if event type requires a smart contract token.
|
||||
const [ethEnabled, toggleEthEnabled] = useState<boolean>(false);
|
||||
const { addContract } = useContracts();
|
||||
const { t } = useLocale();
|
||||
|
||||
const connectMetamask = useCallback(async () => {
|
||||
if (window.ethereum && typeof window.ethereum.request === "function") {
|
||||
await window.ethereum.request({ method: "eth_requestAccounts" });
|
||||
window.web3 = new Web3(window.ethereum);
|
||||
toggleEthEnabled(true);
|
||||
} else {
|
||||
toggleEthEnabled(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const verifyWallet = useCallback(async () => {
|
||||
try {
|
||||
if (!window.web3) throw new Error("MetaMask browser extension is not installed");
|
||||
const contract = new window.web3.eth.Contract(genericAbi as AbiItem[], props.smartContractAddress);
|
||||
const balance = await contract.methods.balanceOf(window.ethereum.selectedAddress).call();
|
||||
const hasToken = balance > 0;
|
||||
|
||||
if (!hasToken)
|
||||
throw new Error("Specified wallet does not own any tokens belonging to this smart contract");
|
||||
|
||||
const [account] = await window.web3.eth.getAccounts();
|
||||
const signature = await window.web3.eth.personal.sign(AUTH_MESSAGE, account, "");
|
||||
addContract({ address: props.smartContractAddress, signature });
|
||||
await verifyAccount(signature, account);
|
||||
props.setEvtsToVerify((prevState: EvtsToVerify) => ({ ...prevState, [props.id]: hasToken }));
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : "An error has occurred";
|
||||
showToast(message, "error");
|
||||
}
|
||||
}, [props, addContract]);
|
||||
|
||||
// @TODO: Show error on either of buttons if fails. Yup schema already contains the error message.
|
||||
const successButton = useMemo(() => {
|
||||
if (props.verified) {
|
||||
Router.push(props.pathname);
|
||||
}
|
||||
|
||||
return <div />;
|
||||
}, [props.pathname, props.verified]);
|
||||
|
||||
const verifyButton = useMemo(() => {
|
||||
return (
|
||||
<Button color="secondary" onClick={verifyWallet} type="button" id="hasToken">
|
||||
<img className="mr-1 h-5" src="/api/app-store/metamask/icon.svg" alt="MetaMask" />
|
||||
{t("verify_wallet")}
|
||||
</Button>
|
||||
);
|
||||
}, [verifyWallet, t]);
|
||||
|
||||
const connectButton = useMemo(() => {
|
||||
return (
|
||||
<Button color="secondary" onClick={connectMetamask} type="button">
|
||||
{
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img className="mr-1 h-5" src="/api/app-store/metamask/icon.svg" alt="MetaMask" />
|
||||
}
|
||||
{t("connect_metamask")}
|
||||
</Button>
|
||||
);
|
||||
}, [connectMetamask, t]);
|
||||
|
||||
const oneStepButton = useMemo(() => {
|
||||
return (
|
||||
<Button
|
||||
color="secondary"
|
||||
type="button"
|
||||
onClick={async () => {
|
||||
await connectMetamask();
|
||||
await verifyWallet();
|
||||
}}>
|
||||
{
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img className="mr-1 h-5" src="/api/app-store/metamask/icon.svg" alt="MetaMask" />
|
||||
}
|
||||
{t("verify_wallet")}
|
||||
</Button>
|
||||
);
|
||||
}, [connectMetamask, verifyWallet, t]);
|
||||
|
||||
const determineButton = useCallback(() => {
|
||||
// Did it in an extra function for some added readability, but this can be done in a ternary depending on preference
|
||||
if (props.oneStep) {
|
||||
return props.verified ? successButton : oneStepButton;
|
||||
} else {
|
||||
if (ethEnabled) {
|
||||
return props.verified ? successButton : verifyButton;
|
||||
} else {
|
||||
return connectButton;
|
||||
}
|
||||
}
|
||||
}, [props.verified, successButton, oneStepButton, connectButton, ethEnabled, props.oneStep, verifyButton]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform opacity-0 transition-opacity group-hover:opacity-100 dark:bg-gray-900"
|
||||
id={`crypto-${props.id}`}>
|
||||
{determineButton()}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default withLicenseRequired(CryptoSection);
|
|
@ -1,48 +0,0 @@
|
|||
import noop from "lodash/noop";
|
||||
import { createContext, ReactNode, useContext } from "react";
|
||||
|
||||
import { localStorage } from "@calcom/lib/webstorage";
|
||||
|
||||
type contractsContextType = {
|
||||
contracts: Record<string, string>;
|
||||
addContract: (payload: addContractsPayload) => void;
|
||||
};
|
||||
|
||||
const contractsContextDefaultValue: contractsContextType = {
|
||||
contracts: {},
|
||||
addContract: noop,
|
||||
};
|
||||
|
||||
const ContractsContext = createContext<contractsContextType>(contractsContextDefaultValue);
|
||||
|
||||
export function useContracts() {
|
||||
return useContext(ContractsContext);
|
||||
}
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
interface addContractsPayload {
|
||||
address: string;
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export function ContractsProvider({ children }: Props) {
|
||||
const addContract = (payload: addContractsPayload) => {
|
||||
localStorage.setItem(
|
||||
"contracts",
|
||||
JSON.stringify({
|
||||
...JSON.parse(localStorage.getItem("contracts") || "{}"),
|
||||
[payload.address]: payload.signature,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const value = {
|
||||
contracts: typeof window !== "undefined" ? JSON.parse(localStorage.getItem("contracts") || "{}") : {},
|
||||
addContract,
|
||||
};
|
||||
|
||||
return <ContractsContext.Provider value={value}>{children}</ContractsContext.Provider>;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import Web3 from "web3";
|
||||
|
||||
export const AUTH_MESSAGE =
|
||||
"I authorize the use of my Ethereum address for the purposes of this application.";
|
||||
|
||||
const verifyAccount = async (signature: string, address: string) => {
|
||||
const web3 = new Web3();
|
||||
const signingAddress = await web3.eth.accounts.recover(AUTH_MESSAGE, signature);
|
||||
if (!(address.toLowerCase() === signingAddress.toLowerCase())) throw new Error("Failed to verify address");
|
||||
};
|
||||
|
||||
export default verifyAccount;
|
|
@ -75,10 +75,6 @@ const commons = {
|
|||
schedulingType: SchedulingType.COLLECTIVE,
|
||||
seatsPerTimeSlot: null,
|
||||
id: 0,
|
||||
metadata: {
|
||||
smartContractAddress: "",
|
||||
},
|
||||
isWeb3Active: false,
|
||||
hideCalendarNotes: false,
|
||||
recurringEvent: null,
|
||||
destinationCalendar: null,
|
||||
|
@ -88,6 +84,7 @@ const commons = {
|
|||
userId: 0,
|
||||
workflows: [],
|
||||
users: [user],
|
||||
metadata: {},
|
||||
};
|
||||
|
||||
const min15Event = {
|
||||
|
|
|
@ -266,7 +266,6 @@ export default async function main() {
|
|||
|
||||
// Web3 apps
|
||||
await createApp("huddle01", "huddle01video", ["web3", "video"], "huddle01_video");
|
||||
await createApp("metamask", "metamask", ["web3"], "metamask_web3");
|
||||
// Messaging apps
|
||||
if (process.env.SLACK_CLIENT_ID && process.env.SLACK_CLIENT_SECRET && process.env.SLACK_SIGNING_SECRET) {
|
||||
await createApp("slack", "slackmessaging", ["messaging"], "slack_messaging", {
|
||||
|
|
|
@ -62,12 +62,6 @@ export const stringToDayjs = z.string().transform((val) => dayjs(val));
|
|||
export const bookingCreateBodySchema = z.object({
|
||||
email: z.string(),
|
||||
end: z.string(),
|
||||
web3Details: z
|
||||
.object({
|
||||
userWallet: z.string(),
|
||||
userSignature: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
eventTypeId: z.number(),
|
||||
eventTypeSlug: z.string().optional(),
|
||||
guests: z.array(z.string()).optional(),
|
||||
|
|
|
@ -638,46 +638,6 @@ const loggedInViewerRouter = createProtectedRouter()
|
|||
});
|
||||
},
|
||||
})
|
||||
.mutation("enableOrDisableWeb3", {
|
||||
input: z.object({}),
|
||||
async resolve({ ctx }) {
|
||||
const { user } = ctx;
|
||||
const where = { userId: user.id, type: "metamask_web3" };
|
||||
|
||||
const web3Credential = await ctx.prisma.credential.findFirst({
|
||||
where,
|
||||
select: {
|
||||
id: true,
|
||||
key: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (web3Credential) {
|
||||
const deleted = await ctx.prisma.credential.delete({
|
||||
where: {
|
||||
id: web3Credential.id,
|
||||
},
|
||||
});
|
||||
return {
|
||||
...deleted,
|
||||
key: {
|
||||
...(deleted.key as JSONObject),
|
||||
isWeb3Active: false,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return ctx.prisma.credential.create({
|
||||
data: {
|
||||
type: "metamask_web3",
|
||||
key: {
|
||||
isWeb3Active: true,
|
||||
} as unknown as Prisma.InputJsonObject,
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
})
|
||||
.query("integrations", {
|
||||
input: z.object({
|
||||
variant: z.string().optional(),
|
||||
|
@ -726,24 +686,6 @@ const loggedInViewerRouter = createProtectedRouter()
|
|||
return app;
|
||||
},
|
||||
})
|
||||
.query("web3Integration", {
|
||||
async resolve({ ctx }) {
|
||||
const { user } = ctx;
|
||||
|
||||
const where = { userId: user.id, type: "metamask_web3" };
|
||||
|
||||
const web3Credential = await ctx.prisma.credential.findFirst({
|
||||
where,
|
||||
select: {
|
||||
key: true,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
isWeb3Active: web3Credential ? (web3Credential.key as JSONObject).isWeb3Active : false,
|
||||
};
|
||||
},
|
||||
})
|
||||
.mutation("updateProfile", {
|
||||
input: z.object({
|
||||
username: z.string().optional(),
|
||||
|
|
120
yarn.lock
120
yarn.lock
|
@ -3188,38 +3188,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b"
|
||||
integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==
|
||||
|
||||
"@metamask/object-multiplex@^1.1.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/object-multiplex/-/object-multiplex-1.2.0.tgz#38fc15c142f61939391e1b9a8eed679696c7e4f4"
|
||||
integrity sha512-hksV602d3NWE2Q30Mf2Np1WfVKaGqfJRy9vpHAmelbaD0OkDt06/0KQkRR6UVYdMbTbkuEu8xN5JDUU80inGwQ==
|
||||
dependencies:
|
||||
end-of-stream "^1.4.4"
|
||||
once "^1.4.0"
|
||||
readable-stream "^2.3.3"
|
||||
|
||||
"@metamask/providers@^8.1.1":
|
||||
version "8.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/providers/-/providers-8.1.1.tgz#7b0dbb54700c949aafba24c9b98e6f4e9d81f325"
|
||||
integrity sha512-CG1sAuD6Mp4MZ5U90anf1FT0moDbStGXT+80TQFYXJbBeTQjhp321WgC/F2IgIJ3mFqOiByC3MQHLuunEVMQOA==
|
||||
dependencies:
|
||||
"@metamask/object-multiplex" "^1.1.0"
|
||||
"@metamask/safe-event-emitter" "^2.0.0"
|
||||
"@types/chrome" "^0.0.136"
|
||||
detect-browser "^5.2.0"
|
||||
eth-rpc-errors "^4.0.2"
|
||||
extension-port-stream "^2.0.1"
|
||||
fast-deep-equal "^2.0.1"
|
||||
is-stream "^2.0.0"
|
||||
json-rpc-engine "^6.1.0"
|
||||
json-rpc-middleware-stream "^3.0.0"
|
||||
pump "^3.0.0"
|
||||
webextension-polyfill-ts "^0.25.0"
|
||||
|
||||
"@metamask/safe-event-emitter@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz#af577b477c683fad17c619a78208cede06f9605c"
|
||||
integrity sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==
|
||||
|
||||
"@microsoft/microsoft-graph-types-beta@0.15.0-preview":
|
||||
version "0.15.0-preview"
|
||||
resolved "https://registry.yarnpkg.com/@microsoft/microsoft-graph-types-beta/-/microsoft-graph-types-beta-0.15.0-preview.tgz#fed0a99be4e1151d566cf063f024913fb48640cd"
|
||||
|
@ -5949,14 +5917,6 @@
|
|||
"@types/node" "*"
|
||||
"@types/responselike" "*"
|
||||
|
||||
"@types/chrome@^0.0.136":
|
||||
version "0.0.136"
|
||||
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.136.tgz#7c011b9f997b0156f25a140188a0c5689d3f368f"
|
||||
integrity sha512-XDEiRhLkMd+SB7Iw3ZUIj/fov3wLd4HyTdLltVszkgl1dBfc3Rb7oPMVZ2Mz2TLqnF7Ow+StbR8E7r9lqpb4DA==
|
||||
dependencies:
|
||||
"@types/filesystem" "*"
|
||||
"@types/har-format" "*"
|
||||
|
||||
"@types/connect@*":
|
||||
version "3.4.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
|
||||
|
@ -6065,18 +6025,6 @@
|
|||
"@types/qs" "*"
|
||||
"@types/serve-static" "*"
|
||||
|
||||
"@types/filesystem@*":
|
||||
version "0.0.32"
|
||||
resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.32.tgz#307df7cc084a2293c3c1a31151b178063e0a8edf"
|
||||
integrity sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ==
|
||||
dependencies:
|
||||
"@types/filewriter" "*"
|
||||
|
||||
"@types/filewriter@*":
|
||||
version "0.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.29.tgz#a48795ecadf957f6c0d10e0c34af86c098fa5bee"
|
||||
integrity sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ==
|
||||
|
||||
"@types/glidejs__glide@^3.4.2":
|
||||
version "3.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/glidejs__glide/-/glidejs__glide-3.4.2.tgz#fb486e376aab88788e09bbdeb81f89dcf363be1c"
|
||||
|
@ -6102,11 +6050,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/gtag.js/-/gtag.js-0.0.10.tgz#ac90d9b79c00daac447725a4b78ec1c398796760"
|
||||
integrity sha512-98Hy7woUb3jMAMXkZQwfIOYNyfxmI0+U4m0PpCGdnd/FHk0tDpQFCqgXdNkdEoXsKkcGya/2Gew1cAJjKJspVw==
|
||||
|
||||
"@types/har-format@*":
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.8.tgz#e6908b76d4c88be3db642846bb8b455f0bfb1c4e"
|
||||
integrity sha512-OP6L9VuZNdskgNN3zFQQ54ceYD8OLq5IbqO4VK91ORLfOm7WdT/CiT/pHEBSQEqCInJ2y3O6iCm/zGtPElpgJQ==
|
||||
|
||||
"@types/hast@^2.0.0":
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc"
|
||||
|
@ -10183,11 +10126,6 @@ detab@2.0.4:
|
|||
dependencies:
|
||||
repeat-string "^1.5.4"
|
||||
|
||||
detect-browser@^5.2.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca"
|
||||
integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==
|
||||
|
||||
detect-element-overflow@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-element-overflow/-/detect-element-overflow-1.2.0.tgz#86e504292ffedc3aef813395fbdf0261aaf6afa9"
|
||||
|
@ -10590,7 +10528,7 @@ encoding@0.1.12:
|
|||
dependencies:
|
||||
iconv-lite "~0.4.13"
|
||||
|
||||
end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.4:
|
||||
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
||||
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
|
||||
|
@ -11461,13 +11399,6 @@ eth-lib@^0.1.26:
|
|||
ws "^3.0.0"
|
||||
xhr-request-promise "^0.1.2"
|
||||
|
||||
eth-rpc-errors@^4.0.2:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz#6ddb6190a4bf360afda82790bb7d9d5e724f423a"
|
||||
integrity sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==
|
||||
dependencies:
|
||||
fast-safe-stringify "^2.0.6"
|
||||
|
||||
ethereum-bloom-filters@^1.0.6:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a"
|
||||
|
@ -11811,13 +11742,6 @@ extend@^3.0.0, extend@^3.0.2, extend@~3.0.2:
|
|||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
|
||||
extension-port-stream@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/extension-port-stream/-/extension-port-stream-2.0.1.tgz#d374820c581418c2275d3c4439ade0b82c4cfac6"
|
||||
integrity sha512-ltrv4Dh/979I04+D4Te6TFygfRSOc5EBzzlHRldWMS8v73V80qWluxH88hqF0qyUsBXTb8NmzlmSipcre6a+rg==
|
||||
dependencies:
|
||||
webextension-polyfill-ts "^0.22.0"
|
||||
|
||||
external-editor@^3.0.3:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
|
||||
|
@ -11851,11 +11775,6 @@ extsprintf@^1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07"
|
||||
integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
|
||||
|
||||
fast-deep-equal@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
|
||||
|
||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
|
@ -11919,7 +11838,7 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
|
|||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
||||
|
||||
fast-safe-stringify@^2.0.6, fast-safe-stringify@^2.0.7:
|
||||
fast-safe-stringify@^2.0.7:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
|
||||
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
|
||||
|
@ -15196,22 +15115,6 @@ json-pointer@0.6.2:
|
|||
dependencies:
|
||||
foreach "^2.0.4"
|
||||
|
||||
json-rpc-engine@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393"
|
||||
integrity sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==
|
||||
dependencies:
|
||||
"@metamask/safe-event-emitter" "^2.0.0"
|
||||
eth-rpc-errors "^4.0.2"
|
||||
|
||||
json-rpc-middleware-stream@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/json-rpc-middleware-stream/-/json-rpc-middleware-stream-3.0.0.tgz#8540331d884f36b9e0ad31054cc68ac6b5a89b52"
|
||||
integrity sha512-JmZmlehE0xF3swwORpLHny/GvW3MZxCsb2uFNBrn8TOqMqivzCfz232NSDLLOtIQlrPlgyEjiYpyzyOPFOzClw==
|
||||
dependencies:
|
||||
"@metamask/safe-event-emitter" "^2.0.0"
|
||||
readable-stream "^2.3.3"
|
||||
|
||||
json-schema-traverse@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||
|
@ -23930,25 +23833,6 @@ webcrypto-core@^1.4.0:
|
|||
pvtsutils "^1.2.2"
|
||||
tslib "^2.3.1"
|
||||
|
||||
webextension-polyfill-ts@^0.22.0:
|
||||
version "0.22.0"
|
||||
resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.22.0.tgz#86cfd7bab4d9d779d98c8340983f4b691b2343f3"
|
||||
integrity sha512-3P33ClMwZ/qiAT7UH1ROrkRC1KM78umlnPpRhdC/292UyoTTW9NcjJEqDsv83HbibcTB6qCtpVeuB2q2/oniHQ==
|
||||
dependencies:
|
||||
webextension-polyfill "^0.7.0"
|
||||
|
||||
webextension-polyfill-ts@^0.25.0:
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.25.0.tgz#fff041626365dbd0e29c40b197e989a55ec221ca"
|
||||
integrity sha512-ikQhwwHYkpBu00pFaUzIKY26I6L87DeRI+Q6jBT1daZUNuu8dSrg5U9l/ZbqdaQ1M/TTSPKeAa3kolP5liuedw==
|
||||
dependencies:
|
||||
webextension-polyfill "^0.7.0"
|
||||
|
||||
webextension-polyfill@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.7.0.tgz#0df1120ff0266056319ce1a622b09ad8d4a56505"
|
||||
integrity sha512-su48BkMLxqzTTvPSE1eWxKToPS2Tv5DLGxKexLEVpwFd6Po6N8hhSLIvG6acPAg7qERoEaDL+Y5HQJeJeml5Aw==
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
|
|
Loading…
Reference in New Issue
Block a user