Skip to content

Commit 758023c

Browse files
Beta Docs (#1)
Co-authored-by: Kautuk Kundan <[email protected]>
1 parent a624755 commit 758023c

File tree

79 files changed

+6621
-196
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+6621
-196
lines changed

docs/components/ConnectWallet.tsx

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { ConnectButton } from "@rainbow-me/rainbowkit";
2+
import { SignupForm } from "./SignupForm";
3+
4+
export const ConnectWallet = () => {
5+
return (
6+
<ConnectButton.Custom>
7+
{({
8+
account,
9+
chain,
10+
openAccountModal,
11+
openChainModal,
12+
openConnectModal,
13+
authenticationStatus,
14+
mounted,
15+
}) => {
16+
const ready = mounted && authenticationStatus !== "loading";
17+
const connected =
18+
ready &&
19+
account &&
20+
chain &&
21+
(!authenticationStatus || authenticationStatus === "authenticated");
22+
return (
23+
<div
24+
{...(!ready && {
25+
"aria-hidden": true,
26+
style: {
27+
opacity: 0,
28+
pointerEvents: "none",
29+
userSelect: "none",
30+
},
31+
})}
32+
>
33+
{(() => {
34+
if (!connected) {
35+
return (
36+
<div className="flex items-center justify-center">
37+
<div className="bg-teal-connect opacity-25 w-[180px] h-10 rounded-lg" />
38+
<button
39+
onClick={openConnectModal}
40+
type="button"
41+
className="primary bg-teal-connect w-44 h-9 px-4 rounded-lg absolute text-black font-jetbrains font-bold"
42+
>
43+
Connect Wallet
44+
</button>
45+
</div>
46+
);
47+
}
48+
if (chain.unsupported) {
49+
return (
50+
<div className="flex items-center justify-center">
51+
<div className="bg-error-med opacity-25 w-[180px] h-10 rounded-lg" />
52+
<button
53+
onClick={openChainModal}
54+
type="button"
55+
className="primary bg-error-med w-44 h-9 px-4 rounded-lg absolute text-black font-jetbrains font-bold"
56+
>
57+
Wrong network
58+
</button>
59+
</div>
60+
);
61+
}
62+
return <SignupForm />;
63+
})()}
64+
</div>
65+
);
66+
}}
67+
</ConnectButton.Custom>
68+
);
69+
};

docs/components/Input.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { UseFormRegister } from "react-hook-form";
2+
import { getRegex } from "../utils";
3+
4+
interface InputProps {
5+
formKey: string;
6+
label: string;
7+
placeholder: string;
8+
paramType: string;
9+
register: UseFormRegister<any>;
10+
defaultValue?: string;
11+
}
12+
13+
export const Input: React.FC<InputProps> = ({
14+
formKey,
15+
label,
16+
placeholder,
17+
defaultValue,
18+
paramType,
19+
register,
20+
}) => {
21+
return (
22+
<div className="flex flex-col gap-2">
23+
<span className="text-white-44 text-sm">{label}</span>
24+
<input
25+
disabled={label === "Wallet"}
26+
className="p-2 border text-sm placeholder-white-44 border-grey-elevation-4 text-white bg-grey-elevation-2 focus:border-teal-primary rounded-lg outline-none"
27+
placeholder={placeholder}
28+
{...register(formKey, {
29+
required: "required",
30+
pattern: {
31+
value: getRegex(paramType),
32+
message: "Invalid input",
33+
},
34+
value: defaultValue || "",
35+
setValueAs: (value) =>
36+
paramType === "uint256"
37+
? value === ""
38+
? ""
39+
: isNaN(Number(value))
40+
? value
41+
: Number(value)
42+
: value,
43+
})}
44+
/>
45+
</div>
46+
);
47+
};

docs/components/SignupForm.tsx

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import { useEffect, useState } from "react";
2+
import { useForm } from "react-hook-form";
3+
import { keccak256, toBytes } from "viem";
4+
// import { Callout } from "vocs/components";
5+
import { useAccount, useSignTypedData } from "wagmi";
6+
import { Input } from "./Input";
7+
8+
const hashFormData = (formData: Record<string, any>) => {
9+
return keccak256(toBytes(JSON.stringify(formData)));
10+
};
11+
12+
const MRU_API = "https://api.beta1.stf.xyz";
13+
14+
const registrationSchema = [
15+
{
16+
name: "Name",
17+
key: "name",
18+
type: "string",
19+
},
20+
{
21+
name: "Wallet",
22+
key: "wallet",
23+
type: "address",
24+
},
25+
{
26+
name: "Discord Username",
27+
key: "discord",
28+
type: "string",
29+
},
30+
{
31+
name: "GitHub Username",
32+
key: "github",
33+
type: "string",
34+
},
35+
{
36+
name: "NPM Username",
37+
key: "npm",
38+
type: "string",
39+
},
40+
{
41+
name: "What vertical are you in?",
42+
key: "vertical",
43+
type: "string",
44+
},
45+
{
46+
name: "What do you plan to build?",
47+
key: "planToBuild",
48+
type: "string",
49+
},
50+
{
51+
name: "How does Stackr fit into your project?",
52+
key: "stackrFit",
53+
type: "string",
54+
},
55+
{
56+
name: "What is your aspirational idea?",
57+
key: "aspirationalIdea",
58+
type: "string",
59+
},
60+
];
61+
62+
export const SignupForm = () => {
63+
const { signTypedDataAsync } = useSignTypedData();
64+
const { address } = useAccount();
65+
const { register, handleSubmit, reset, watch, formState } = useForm<any>();
66+
const watcher = watch();
67+
const [isAnyFieldEmpty, setIsAnyFieldEmpty] = useState(false);
68+
const [hasApplied, setHasApplied] = useState(false);
69+
70+
const onSubmit = async (details: any) => {
71+
const hash = hashFormData(details);
72+
73+
const inputs = {
74+
hash,
75+
};
76+
77+
const schemaData = await fetch(`${MRU_API}/schema`);
78+
const { domain, types } = await schemaData.json();
79+
const signature = await signTypedDataAsync({
80+
domain,
81+
types: types,
82+
primaryType: Object.keys(types)[0],
83+
message: inputs,
84+
});
85+
86+
const payload = { signature, msgSender: address, inputs, details };
87+
88+
const res = await fetch(`${MRU_API}/register`, {
89+
method: "POST",
90+
headers: {
91+
"Content-Type": "application/json",
92+
},
93+
body: JSON.stringify(payload),
94+
});
95+
96+
if (res.status === 201) {
97+
setHasApplied(true);
98+
reset();
99+
}
100+
};
101+
102+
const renderForm = () => {
103+
const { isSubmitting, errors, isValid } = formState;
104+
const isDisabled = isSubmitting || !isValid || isAnyFieldEmpty;
105+
106+
useEffect(() => {
107+
const anyFieldEmpty = Object.values(watcher).some(
108+
(field) => field === ""
109+
);
110+
setIsAnyFieldEmpty(anyFieldEmpty);
111+
}, [watcher, errors]);
112+
113+
return (
114+
<form
115+
className="flex flex-col gap-6 w-full overflow-scroll"
116+
onSubmit={handleSubmit(onSubmit)}
117+
>
118+
{registrationSchema.map(({ key, type, name }) => (
119+
<Input
120+
key={key}
121+
formKey={key}
122+
register={register}
123+
placeholder={type}
124+
defaultValue={key === "wallet" ? address : ""}
125+
label={name}
126+
paramType={type}
127+
/>
128+
))}
129+
130+
<div className="bg-teal-connect opacity-25 w-[180px] h-6 rounded-lg" />
131+
<div className="flex items-center justify-center">
132+
<button
133+
type="submit"
134+
disabled={isDisabled}
135+
className="primary bg-teal-connect w-44 h-9 px-4 rounded-lg absolute text-black font-jetbrains font-bold"
136+
>
137+
{isSubmitting ? "Applying..." : "Sign & Apply"}
138+
</button>
139+
</div>
140+
<div className="bg-teal-connect opacity-25 w-[180px] h-6 rounded-lg" />
141+
</form>
142+
);
143+
};
144+
145+
return (
146+
<div className="font-geist">
147+
{hasApplied ? (
148+
// <Callout className="text-center" type="info">
149+
<>
150+
Thanks for applying, we'll review your application and "drop" access
151+
in next few days!
152+
</>
153+
) : (
154+
// </Callout>
155+
renderForm()
156+
)}
157+
</div>
158+
);
159+
};

docs/components/Web3Provider.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {
2+
RainbowKitProvider,
3+
darkTheme,
4+
getDefaultConfig,
5+
} from "@rainbow-me/rainbowkit";
6+
import "@rainbow-me/rainbowkit/styles.css";
7+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
8+
import { WagmiProvider } from "wagmi";
9+
import { sepolia } from "wagmi/chains";
10+
11+
const config = getDefaultConfig({
12+
appName: "Stackr Explorer",
13+
projectId: "YOUR_PROJECT_ID",
14+
chains: [sepolia],
15+
ssr: true, // If your dApp uses server side rendering (SSR)
16+
});
17+
18+
const queryClient = new QueryClient();
19+
20+
export const Web3Provider: React.FC<{ children: React.ReactNode }> = ({
21+
children,
22+
}) => {
23+
return (
24+
<WagmiProvider config={config}>
25+
<QueryClientProvider client={queryClient}>
26+
<RainbowKitProvider
27+
theme={darkTheme({
28+
accentColor: "#00CECE",
29+
accentColorForeground: "black",
30+
borderRadius: "small",
31+
fontStack: "system",
32+
overlayBlur: "small",
33+
})}
34+
>
35+
{children}
36+
</RainbowKitProvider>
37+
</QueryClientProvider>
38+
</WagmiProvider>
39+
);
40+
};

docs/layout.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { ReactNode } from "react";
2+
import { Web3Provider } from "./components/Web3Provider";
3+
4+
interface LayoutProps {
5+
children: ReactNode;
6+
}
7+
8+
export default function Layout({ children }: LayoutProps) {
9+
return <Web3Provider>{children}</Web3Provider>;
10+
}

0 commit comments

Comments
 (0)