forked from cerc-io/snowballtools-base
Switch from cra to vite
This commit is contained in:
@@ -1,51 +1,51 @@
|
||||
import React from 'react';
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||
import React from "react";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
|
||||
import Projects from './pages/org-slug';
|
||||
import Settings from './pages/org-slug/Settings';
|
||||
import Projects from "./pages/org-slug";
|
||||
import Settings from "./pages/org-slug/Settings";
|
||||
import {
|
||||
projectsRoutesWithSearch,
|
||||
projectsRoutesWithoutSearch,
|
||||
} from './pages/org-slug/projects/routes';
|
||||
import ProjectSearchLayout from './layouts/ProjectSearch';
|
||||
import Index from './pages';
|
||||
import Login from './pages/Login';
|
||||
import { DashboardLayout } from 'pages/org-slug/layout';
|
||||
} from "./pages/org-slug/projects/routes";
|
||||
import ProjectSearchLayout from "./layouts/ProjectSearch";
|
||||
import Index from "./pages";
|
||||
import Login from "./pages/Login";
|
||||
import { DashboardLayout } from "./pages/org-slug/layout";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: ':orgSlug',
|
||||
path: ":orgSlug",
|
||||
element: <DashboardLayout />,
|
||||
children: [
|
||||
{
|
||||
element: <ProjectSearchLayout />,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
path: "",
|
||||
element: <Projects />,
|
||||
},
|
||||
{
|
||||
path: 'projects',
|
||||
path: "projects",
|
||||
children: projectsRoutesWithSearch,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'settings',
|
||||
path: "settings",
|
||||
element: <Settings />,
|
||||
},
|
||||
{
|
||||
path: 'projects',
|
||||
path: "projects",
|
||||
children: projectsRoutesWithoutSearch,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
path: "/",
|
||||
element: <Index />,
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
path: "/login",
|
||||
element: <Login />,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
export default [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Progressive Web App (PWA)',
|
||||
icon: 'pwa',
|
||||
repoFullName: `${process.env.REACT_APP_GITHUB_PWA_TEMPLATE_REPO}`,
|
||||
id: "1",
|
||||
name: "Progressive Web App (PWA)",
|
||||
icon: "pwa",
|
||||
repoFullName: `${import.meta.env.VITE_GITHUB_PWA_TEMPLATE_REPO}`,
|
||||
isComingSoon: false,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Image Upload PWA',
|
||||
icon: 'pwa',
|
||||
repoFullName: `${process.env.REACT_APP_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO}`,
|
||||
id: "2",
|
||||
name: "Image Upload PWA",
|
||||
icon: "pwa",
|
||||
repoFullName: `${import.meta.env.VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO}`,
|
||||
isComingSoon: false,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Kotlin',
|
||||
icon: 'kotlin',
|
||||
repoFullName: '',
|
||||
id: "3",
|
||||
name: "Kotlin",
|
||||
icon: "kotlin",
|
||||
repoFullName: "",
|
||||
isComingSoon: true,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'React Native',
|
||||
icon: 'react-native',
|
||||
repoFullName: '',
|
||||
id: "4",
|
||||
name: "React Native",
|
||||
icon: "react-native",
|
||||
repoFullName: "",
|
||||
isComingSoon: true,
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
name: 'Swift',
|
||||
icon: 'swift',
|
||||
repoFullName: '',
|
||||
id: "5",
|
||||
name: "Swift",
|
||||
icon: "swift",
|
||||
repoFullName: "",
|
||||
isComingSoon: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { StepperNav } from 'vertical-stepper-nav';
|
||||
import React from "react";
|
||||
import { StepperNav } from "./VerticalStepper";
|
||||
|
||||
const COLOR_COMPLETED = '#059669';
|
||||
const COLOR_ACTIVE = '#CFE6FC';
|
||||
const COLOR_NOT_STARTED = '#F1F5F9';
|
||||
const COLOR_COMPLETED = "#059669";
|
||||
const COLOR_ACTIVE = "#CFE6FC";
|
||||
const COLOR_NOT_STARTED = "#F1F5F9";
|
||||
|
||||
interface StepperValue {
|
||||
step: number;
|
||||
@@ -25,8 +25,8 @@ const Stepper = ({ activeStep, stepperValues }: StepperProps) => {
|
||||
<div
|
||||
className={`text-sm ${
|
||||
activeStep === stepperValue.step
|
||||
? 'text-black font-semibold'
|
||||
: 'text-gray-600'
|
||||
? "text-black font-semibold"
|
||||
: "text-gray-600"
|
||||
}`}
|
||||
>
|
||||
{stepperValue.label}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
import React from 'react';
|
||||
import * as CSS from 'csstype';
|
||||
|
||||
//
|
||||
// Nav
|
||||
//
|
||||
export interface IStepDescription {
|
||||
stepContent: () => JSX.Element;
|
||||
stepStateColor?: string;
|
||||
stepStatusCircleSize?: number;
|
||||
onClickHandler?: () => void | undefined;
|
||||
}
|
||||
|
||||
export interface IStepperNavProps {
|
||||
steps: IStepDescription[];
|
||||
}
|
||||
|
||||
export const StepperNav = (props: IStepperNavProps): JSX.Element => {
|
||||
return (
|
||||
<nav>
|
||||
{props.steps.map(
|
||||
(
|
||||
{ stepContent, stepStateColor, onClickHandler, stepStatusCircleSize },
|
||||
index,
|
||||
) => (
|
||||
<div key={index}>
|
||||
<Step
|
||||
stepContent={stepContent}
|
||||
statusColor={stepStateColor}
|
||||
onClickHandler={onClickHandler}
|
||||
statusCircleSize={stepStatusCircleSize}
|
||||
/>
|
||||
{index !== props.steps.length - 1 && (
|
||||
<div
|
||||
style={{
|
||||
paddingLeft: `${(stepStatusCircleSize ?? 16) / 2 + 1}px`,
|
||||
}}
|
||||
>
|
||||
<Separator />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
)}
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
//
|
||||
// Separator
|
||||
//
|
||||
const separatorStyles = {
|
||||
height: '5vh',
|
||||
width: 2,
|
||||
border: '1px solid #E1E1E1',
|
||||
background: '#E1E1E1',
|
||||
};
|
||||
|
||||
export interface ISeparator {
|
||||
height?: string | number;
|
||||
}
|
||||
|
||||
export const Separator = ({ height }: ISeparator): JSX.Element => {
|
||||
return <div style={{ ...separatorStyles, height: height ?? '5vh' }} />;
|
||||
};
|
||||
|
||||
//
|
||||
// Step
|
||||
//
|
||||
export interface IStep {
|
||||
stepContent: () => JSX.Element;
|
||||
statusColor?: string;
|
||||
statusCircleSize?: number;
|
||||
onClickHandler?: (
|
||||
event?: React.MouseEvent<HTMLDivElement>,
|
||||
) => void | undefined;
|
||||
}
|
||||
|
||||
const buttonContainerStyles: CSS.Properties = {
|
||||
display: 'inline-flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: '12px',
|
||||
padding: '2px',
|
||||
cursor: 'pointer',
|
||||
};
|
||||
|
||||
export const Step = ({
|
||||
stepContent,
|
||||
statusColor,
|
||||
statusCircleSize,
|
||||
onClickHandler,
|
||||
}: IStep): JSX.Element => {
|
||||
const circleStyles = {
|
||||
borderRadius: statusCircleSize ?? 16,
|
||||
width: statusCircleSize ?? 16,
|
||||
height: statusCircleSize ?? 16,
|
||||
border: '2px solid #E1E1E1',
|
||||
background: statusColor ?? 'white',
|
||||
};
|
||||
|
||||
const keyDownHandler = (event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (event.keyCode === 13 || event.keyCode === 32) {
|
||||
onClickHandler?.();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
tabIndex={0}
|
||||
onClick={onClickHandler}
|
||||
onKeyDown={keyDownHandler}
|
||||
role="button"
|
||||
style={{ ...buttonContainerStyles }}
|
||||
>
|
||||
<div>
|
||||
<div style={circleStyles} />
|
||||
</div>
|
||||
<div style={{ paddingBottom: 2 }}>{stepContent()}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,23 +1,23 @@
|
||||
import React from 'react';
|
||||
import OauthPopup from 'react-oauth-popup';
|
||||
import React from "react";
|
||||
import OauthPopup from "react-oauth-popup";
|
||||
|
||||
import { useGQLClient } from '../../../context/GQLClientContext';
|
||||
import { Button } from 'components/shared/Button';
|
||||
import { useGQLClient } from "../../../context/GQLClientContext";
|
||||
import { Button } from "../../shared/Button";
|
||||
import {
|
||||
GitIcon,
|
||||
EllipsesIcon,
|
||||
SnowballIcon,
|
||||
GithubIcon,
|
||||
GitTeaIcon,
|
||||
} from 'components/shared/CustomIcon';
|
||||
import { useToast } from 'components/shared/Toast';
|
||||
import { IconWithFrame } from 'components/shared/IconWithFrame';
|
||||
import { Heading } from 'components/shared/Heading';
|
||||
import { MockConnectGitCard } from './MockConnectGitCard';
|
||||
} from "../../shared/CustomIcon";
|
||||
import { useToast } from "../../shared/Toast";
|
||||
import { IconWithFrame } from "../../shared/IconWithFrame";
|
||||
import { Heading } from "../../shared/Heading";
|
||||
import { MockConnectGitCard } from "./MockConnectGitCard";
|
||||
|
||||
const SCOPES = 'repo user';
|
||||
const SCOPES = "repo user";
|
||||
const GITHUB_OAUTH_URL = `https://github.com/login/oauth/authorize?client_id=${
|
||||
process.env.REACT_APP_GITHUB_CLIENT_ID
|
||||
import.meta.env.VITE_GITHUB_CLIENT_ID
|
||||
}&scope=${encodeURIComponent(SCOPES)}`;
|
||||
|
||||
interface ConnectAccountInterface {
|
||||
@@ -39,9 +39,9 @@ const ConnectAccount: React.FC<ConnectAccountInterface> = ({
|
||||
onToken(token);
|
||||
toast({
|
||||
onDismiss: dismiss,
|
||||
id: 'connected-to-github',
|
||||
title: 'The Git account is connected.',
|
||||
variant: 'success',
|
||||
id: "connected-to-github",
|
||||
title: "The Git account is connected.",
|
||||
variant: "success",
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
import { Tabs } from 'components/shared/Tabs';
|
||||
import { Tabs } from "components/shared/Tabs";
|
||||
|
||||
const ConnectAccountTabPanel: React.FC = () => {
|
||||
return (
|
||||
@@ -11,8 +11,8 @@ const ConnectAccountTabPanel: React.FC = () => {
|
||||
>
|
||||
<Tabs.List>
|
||||
{[
|
||||
{ title: 'Import a repository' },
|
||||
{ title: 'Start with a template' },
|
||||
{ title: "Import a repository" },
|
||||
{ title: "Start with a template" },
|
||||
].map(({ title }, index) => (
|
||||
<Tabs.Trigger value={title} key={index}>
|
||||
{title}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
||||
|
||||
import { DeployStep, DeployStatus } from './DeployStep';
|
||||
import { Stopwatch, setStopWatchOffset } from 'components/StopWatch';
|
||||
import { Heading } from 'components/shared/Heading';
|
||||
import { Button } from 'components/shared/Button';
|
||||
import { ClockOutlineIcon, WarningIcon } from 'components/shared/CustomIcon';
|
||||
import { CancelDeploymentDialog } from 'components/projects/Dialog/CancelDeploymentDialog';
|
||||
import { DeployStep, DeployStatus } from "./DeployStep";
|
||||
import { Stopwatch, setStopWatchOffset } from "../../StopWatch";
|
||||
import { Heading } from "../../shared/Heading";
|
||||
import { Button } from "../../shared/Button";
|
||||
import { ClockOutlineIcon, WarningIcon } from "../../shared/CustomIcon";
|
||||
import { CancelDeploymentDialog } from "../../projects/Dialog/CancelDeploymentDialog";
|
||||
|
||||
const TIMEOUT_DURATION = 5000;
|
||||
const Deploy = () => {
|
||||
const [searchParams] = useSearchParams();
|
||||
const projectId = searchParams.get('projectId');
|
||||
const projectId = searchParams.get("projectId");
|
||||
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const handleOpen = () => setOpen(!open);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { Collapse } from '@material-tailwind/react';
|
||||
import { Collapse } from "@material-tailwind/react";
|
||||
|
||||
import { Stopwatch, setStopWatchOffset } from '../../StopWatch';
|
||||
import FormatMillisecond from '../../FormatMilliSecond';
|
||||
import processLogs from '../../../assets/process-logs.json';
|
||||
import { cn } from 'utils/classnames';
|
||||
import { Stopwatch, setStopWatchOffset } from "../../StopWatch";
|
||||
import FormatMillisecond from "../../FormatMilliSecond";
|
||||
import processLogs from "../../../assets/process-logs.json";
|
||||
import { cn } from "utils/classnames";
|
||||
import {
|
||||
CheckRoundFilledIcon,
|
||||
ClockOutlineIcon,
|
||||
@@ -13,15 +13,15 @@ import {
|
||||
LoaderIcon,
|
||||
MinusCircleIcon,
|
||||
PlusIcon,
|
||||
} from 'components/shared/CustomIcon';
|
||||
import { Button } from 'components/shared/Button';
|
||||
import { useToast } from 'components/shared/Toast';
|
||||
import { useIntersectionObserver } from 'usehooks-ts';
|
||||
} from "components/shared/CustomIcon";
|
||||
import { Button } from "components/shared/Button";
|
||||
import { useToast } from "components/shared/Toast";
|
||||
import { useIntersectionObserver } from "usehooks-ts";
|
||||
|
||||
enum DeployStatus {
|
||||
PROCESSING = 'progress',
|
||||
COMPLETE = 'complete',
|
||||
NOT_STARTED = 'notStarted',
|
||||
PROCESSING = "progress",
|
||||
COMPLETE = "complete",
|
||||
NOT_STARTED = "notStarted",
|
||||
}
|
||||
|
||||
interface DeployStepsProps {
|
||||
@@ -52,8 +52,8 @@ const DeployStep = ({
|
||||
{/* Collapisble trigger */}
|
||||
<button
|
||||
className={cn(
|
||||
'flex justify-between w-full py-5 gap-2',
|
||||
disableCollapse && 'cursor-auto',
|
||||
"flex justify-between w-full py-5 gap-2",
|
||||
disableCollapse && "cursor-auto",
|
||||
)}
|
||||
tabIndex={disableCollapse ? -1 : undefined}
|
||||
onClick={() => {
|
||||
@@ -62,7 +62,7 @@ const DeployStep = ({
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className={cn('grow flex items-center gap-3')}>
|
||||
<div className={cn("grow flex items-center gap-3")}>
|
||||
{/* Icon */}
|
||||
<div className="w-6 h-6 grid place-content-center">
|
||||
{status === DeployStatus.NOT_STARTED && (
|
||||
@@ -84,8 +84,8 @@ const DeployStep = ({
|
||||
{/* Title */}
|
||||
<span
|
||||
className={cn(
|
||||
'text-left text-sm md:text-base',
|
||||
status === DeployStatus.PROCESSING && 'text-elements-link',
|
||||
"text-left text-sm md:text-base",
|
||||
status === DeployStatus.PROCESSING && "text-elements-link",
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
@@ -107,7 +107,7 @@ const DeployStep = ({
|
||||
size={15}
|
||||
/>
|
||||
</div>
|
||||
<FormatMillisecond time={Number(processTime)} />{' '}
|
||||
<FormatMillisecond time={Number(processTime)} />{" "}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
@@ -133,15 +133,15 @@ const DeployStep = ({
|
||||
)}
|
||||
|
||||
{/* Copy log button */}
|
||||
<div className={cn('sticky bottom-4 left-1/2 flex justify-center')}>
|
||||
<div className={cn("sticky bottom-4 left-1/2 flex justify-center")}>
|
||||
<Button
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(processLogs.join('\n'));
|
||||
navigator.clipboard.writeText(processLogs.join("\n"));
|
||||
toast({
|
||||
title: 'Logs copied',
|
||||
variant: 'success',
|
||||
id: 'logs',
|
||||
title: "Logs copied",
|
||||
variant: "success",
|
||||
id: "logs",
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -1,83 +1,83 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import { SiweMessage } from 'siwe';
|
||||
import { WagmiProvider } from 'wagmi';
|
||||
import { arbitrum, mainnet } from 'wagmi/chains';
|
||||
import axios from 'axios';
|
||||
import React, { ReactNode } from "react";
|
||||
import { SiweMessage } from "siwe";
|
||||
import { WagmiProvider } from "wagmi";
|
||||
import { arbitrum, mainnet } from "wagmi/chains";
|
||||
import axios from "axios";
|
||||
|
||||
import { createWeb3Modal } from '@web3modal/wagmi/react';
|
||||
import { defaultWagmiConfig } from '@web3modal/wagmi/react/config';
|
||||
import { createSIWEConfig } from '@web3modal/siwe';
|
||||
import { createWeb3Modal } from "@web3modal/wagmi/react";
|
||||
import { defaultWagmiConfig } from "@web3modal/wagmi/react/config";
|
||||
import { createSIWEConfig } from "@web3modal/siwe";
|
||||
import type {
|
||||
SIWECreateMessageArgs,
|
||||
SIWEVerifyMessageArgs,
|
||||
} from '@web3modal/core';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
} from "@web3modal/core";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: process.env.REACT_APP_SERVER_URL,
|
||||
baseURL: import.meta.env.VITE_SERVER_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
"Content-Type": "application/json",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
},
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
const metadata = {
|
||||
name: 'Snowball Tools',
|
||||
description: 'Snowball Tools Dashboard',
|
||||
name: "Snowball Tools",
|
||||
description: "Snowball Tools Dashboard",
|
||||
url: window.location.origin,
|
||||
icons: [
|
||||
'https://raw.githubusercontent.com/snowball-tools/mediakit/main/assets/logo.svg',
|
||||
"https://raw.githubusercontent.com/snowball-tools/mediakit/main/assets/logo.svg",
|
||||
],
|
||||
};
|
||||
|
||||
const chains = [mainnet, arbitrum] as const;
|
||||
const config = defaultWagmiConfig({
|
||||
chains,
|
||||
projectId: process.env.REACT_APP_WALLET_CONNECT_ID,
|
||||
projectId: import.meta.env.VITE_WALLET_CONNECT_ID,
|
||||
metadata,
|
||||
});
|
||||
|
||||
const siweConfig = createSIWEConfig({
|
||||
createMessage: ({ nonce, address, chainId }: SIWECreateMessageArgs) =>
|
||||
new SiweMessage({
|
||||
version: '1',
|
||||
version: "1",
|
||||
domain: window.location.host,
|
||||
uri: window.location.origin,
|
||||
address,
|
||||
chainId,
|
||||
nonce,
|
||||
// Human-readable ASCII assertion that the user will sign, and it must not contain `\n`.
|
||||
statement: 'Sign in With Ethereum.',
|
||||
statement: "Sign in With Ethereum.",
|
||||
}).prepareMessage(),
|
||||
getNonce: async () => {
|
||||
const nonce = (await axiosInstance.get('/auth/nonce')).data;
|
||||
const nonce = (await axiosInstance.get("/auth/nonce")).data;
|
||||
if (!nonce) {
|
||||
throw new Error('Failed to get nonce!');
|
||||
throw new Error("Failed to get nonce!");
|
||||
}
|
||||
|
||||
return nonce;
|
||||
},
|
||||
getSession: async () => {
|
||||
try {
|
||||
const session = (await axiosInstance.get('/auth/session')).data;
|
||||
const session = (await axiosInstance.get("/auth/session")).data;
|
||||
const { address, chainId } = session;
|
||||
|
||||
return { address, chainId };
|
||||
} catch (err) {
|
||||
if (window.location.pathname !== '/login') {
|
||||
window.location.href = '/login';
|
||||
if (window.location.pathname !== "/login") {
|
||||
window.location.href = "/login";
|
||||
}
|
||||
|
||||
throw new Error('Failed to get session!');
|
||||
throw new Error("Failed to get session!");
|
||||
}
|
||||
},
|
||||
verifyMessage: async ({ message, signature }: SIWEVerifyMessageArgs) => {
|
||||
try {
|
||||
const { success } = (
|
||||
await axiosInstance.post('/auth/validate', {
|
||||
await axiosInstance.post("/auth/validate", {
|
||||
message,
|
||||
signature,
|
||||
})
|
||||
@@ -90,28 +90,28 @@ const siweConfig = createSIWEConfig({
|
||||
},
|
||||
signOut: async () => {
|
||||
try {
|
||||
const { success } = (await axiosInstance.post('/auth/logout')).data;
|
||||
const { success } = (await axiosInstance.post("/auth/logout")).data;
|
||||
return success;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSignOut: () => {
|
||||
window.location.href = '/login';
|
||||
window.location.href = "/login";
|
||||
},
|
||||
onSignIn: () => {
|
||||
window.location.href = '/';
|
||||
window.location.href = "/";
|
||||
},
|
||||
});
|
||||
|
||||
if (!process.env.REACT_APP_WALLET_CONNECT_ID) {
|
||||
throw new Error('Error: REACT_APP_WALLET_CONNECT_ID env config is not set');
|
||||
if (!import.meta.env.VITE_WALLET_CONNECT_ID) {
|
||||
throw new Error("Error: REACT_APP_WALLET_CONNECT_ID env config is not set");
|
||||
}
|
||||
|
||||
createWeb3Modal({
|
||||
siweConfig,
|
||||
wagmiConfig: config,
|
||||
projectId: process.env.REACT_APP_WALLET_CONNECT_ID,
|
||||
projectId: import.meta.env.VITE_WALLET_CONNECT_ID,
|
||||
});
|
||||
|
||||
export default function Web3ModalProvider({
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import assert from 'assert';
|
||||
import { GQLClient } from 'gql-client';
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import assert from "assert";
|
||||
import { GQLClient } from "gql-client";
|
||||
|
||||
import { ThemeProvider } from '@material-tailwind/react';
|
||||
import { ThemeProvider } from "@material-tailwind/react";
|
||||
|
||||
import './index.css';
|
||||
import '@fontsource/inter';
|
||||
import '@fontsource-variable/jetbrains-mono';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
import { GQLClientProvider } from './context/GQLClientContext';
|
||||
import { SERVER_GQL_PATH } from './constants';
|
||||
import { Toaster } from 'components/shared/Toast';
|
||||
import Web3ModalProvider from './context/Web3ModalProvider';
|
||||
import "./index.css";
|
||||
import "@fontsource/inter";
|
||||
import "@fontsource-variable/jetbrains-mono";
|
||||
import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import { GQLClientProvider } from "./context/GQLClientContext";
|
||||
import { SERVER_GQL_PATH } from "./constants";
|
||||
import { Toaster } from "components/shared/Toast";
|
||||
import Web3ModalProvider from "./context/Web3ModalProvider";
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement,
|
||||
document.getElementById("root") as HTMLElement,
|
||||
);
|
||||
|
||||
assert(
|
||||
process.env.REACT_APP_SERVER_URL,
|
||||
'REACT_APP_SERVER_URL is not set in env',
|
||||
import.meta.env.VITE_SERVER_URL,
|
||||
"REACT_APP_SERVER_URL is not set in env",
|
||||
);
|
||||
const gqlEndpoint = `${process.env.REACT_APP_SERVER_URL}/${SERVER_GQL_PATH}`;
|
||||
const gqlEndpoint = `${import.meta.env.VITE_SERVER_URL}/${SERVER_GQL_PATH}`;
|
||||
|
||||
const gqlClient = new GQLClient({ gqlEndpoint });
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { useSnowball } from 'utils/use-snowball';
|
||||
|
||||
export const SnowballLogin = () => {
|
||||
const snowball = useSnowball();
|
||||
console.log(snowball);
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen bg-snowball-900 snow">
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<img
|
||||
src="/logo.svg"
|
||||
alt="snowball logo"
|
||||
className="w-32 h-32 rounded-full mb-4"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import { LitGoogleAuth } from "@snowballtools/auth-lit";
|
||||
import { Snowball, SnowballChain } from "@snowballtools/js-sdk";
|
||||
// import { LinkLitAlchemyLight } from '@snowballtools/link-lit-alchemy-light';
|
||||
|
||||
export const DOMAIN = import.meta.env.VITE_DOMAIN || "localhost";
|
||||
export const ORIGIN =
|
||||
import.meta.env.VITE_VERCEL_ENV === "production"
|
||||
? `https://${DOMAIN}`
|
||||
: `http://${DOMAIN}:3000`;
|
||||
|
||||
// prettier-ignore
|
||||
|
||||
export const snowball = Snowball.withAuth(
|
||||
LitGoogleAuth.configure({
|
||||
litReplayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
|
||||
}),
|
||||
).create({
|
||||
initialChain: SnowballChain.sepolia,
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { snowball } from './snowball';
|
||||
|
||||
export function useSnowball() {
|
||||
const [state, setState] = useState(100);
|
||||
|
||||
useEffect(() => {
|
||||
// Subscribe and directly return the unsubscribe function
|
||||
return snowball.subscribe(() => setState(state + 1));
|
||||
}, [snowball]);
|
||||
|
||||
return snowball;
|
||||
}
|
||||
Reference in New Issue
Block a user