Skip to content

Commit

Permalink
Integrated web3-payments on /spaces , added middleware for next-app (#…
Browse files Browse the repository at this point in the history
…115)

* added web3-payments , middleware
  • Loading branch information
mohitejaikumar committed Sep 26, 2024
1 parent 2527659 commit 30dcf77
Show file tree
Hide file tree
Showing 16 changed files with 11,380 additions and 2,056 deletions.
2 changes: 2 additions & 0 deletions next-app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ GOOGLE_CLIENT_SECRET=YOUR_GOOGLE_CLIENT_SECRET
NEXTAUTH_SECRET="YOUR_NEXTAUTH_SECRET"
NEXT_PUBLIC_SECRET="YOUR_NEXTAUTH_SECRET"
NEXT_PUBLIC_WSS_URL="ws://localhost:3000"
NEXT_PUBLIC_PUBLICKEY="YOUR_PUBLIC_KEY"
NEXT_PUBLIC_SOL_PER_PAYMENT="YOUR_SOL_PER_PAYMENT"

# Postgres DB
DATABASE_URL=postgresql://postgres:postgres@postgres:5432/postgres
Expand Down
2 changes: 1 addition & 1 deletion next-app/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { authOptions } from "@/lib/auth-options";

export default async function LandingPage() {
const session = await getServerSession(authOptions);
if (session?.user.id) redirect("/home");


return (
<div className="flex min-h-screen flex-col bg-gradient-to-br from-gray-900 via-purple-900 to-gray-900">
Expand Down
4 changes: 4 additions & 0 deletions next-app/app/spaces/[spaceId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import LoadingScreen from "@/components/LoadingScreen";
import { useRouter } from "next/navigation";


// Default styles that can be overridden by your app
import '@solana/wallet-adapter-react-ui/styles.css';



export default function Component({params:{spaceId}}:{params:{spaceId:string}}) {

Expand Down
6 changes: 5 additions & 1 deletion next-app/components/Appbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { signIn, signOut, useSession } from "next-auth/react";
import { Button } from "@/components/ui/button";
import { useRouter } from "next/navigation";
import { ThemeSwitcher } from "./ThemeSwitcher";
import { WalletMultiButton } from "@solana/wallet-adapter-react-ui";
import Link from "next/link";

export function Appbar({ showThemeSwitch = true }) {

export function Appbar({ showThemeSwitch = true , isSpectator=false }) {
const session = useSession();
const router = useRouter();

Expand All @@ -20,6 +22,7 @@ export function Appbar({ showThemeSwitch = true }) {
Muzer
</div>
<div className="flex items-center gap-x-2">
{isSpectator && <WalletMultiButton/>}
{session.data?.user && (
<Button
className="bg-purple-600 text-white hover:bg-purple-700"
Expand Down Expand Up @@ -57,6 +60,7 @@ export function Appbar({ showThemeSwitch = true }) {
</Link>
</div>
)}

{showThemeSwitch && <ThemeSwitcher />}
</div>
</div>
Expand Down
78 changes: 76 additions & 2 deletions next-app/components/StreamView/AddSongForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card, CardContent } from "@/components/ui/card";
import LiteYouTubeEmbed from "react-lite-youtube-embed";
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction } from "@solana/web3.js";
import { useSession } from "next-auth/react";



type Props = {
inputLink: string;
Expand All @@ -14,7 +19,8 @@ type Props = {
setInputLink: (value: string) => void;
loading: boolean;
enqueueToast: (type: "error" | "success", message: string) => void;
spaceId:string
spaceId:string,
isSpectator:boolean
};

export default function AddSongForm({
Expand All @@ -24,9 +30,13 @@ export default function AddSongForm({
loading,
setLoading,
userId,
spaceId
spaceId,
isSpectator,
}: Props) {
const { sendMessage } = useSocket();
const wallet = useWallet();
const {connection} = useConnection();
const user = useSession().data?.user;

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
Expand All @@ -41,9 +51,61 @@ export default function AddSongForm({
} else {
enqueueToast("error", "Invalid please use specified formate");
}
setLoading(false);
setInputLink("");
};

const handlePayAndPlay = async (e: React.FormEvent) => {
e.preventDefault();

if(!wallet.publicKey || !connection){
enqueueToast("error", "Please connect your wallet");
return;
}
if (!inputLink.match(YT_REGEX)) {
enqueueToast("error", "Invalid please use specified formate");
}
try{
setLoading(true);
const transaction = new Transaction();
transaction.add(
SystemProgram.transfer({
fromPubkey: wallet.publicKey,
toPubkey: new PublicKey(process.env.NEXT_PUBLIC_PUBLICKEY as string),
lamports: Number(process.env.NEXT_PUBLIC_SOL_PER_PAYMENT) * LAMPORTS_PER_SOL,
})
)

// sign Transaction steps
const blockHash = await connection.getLatestBlockhash();
transaction.feePayer = wallet.publicKey;
transaction.recentBlockhash = blockHash.blockhash;
//@ts-ignore
const signed = await wallet.signTransaction(transaction);


const signature = await connection.sendRawTransaction(signed.serialize());

enqueueToast("success", `Transaction signature: ${signature}`);
await connection.confirmTransaction({
blockhash: blockHash.blockhash,
lastValidBlockHeight: blockHash.lastValidBlockHeight,
signature
});
enqueueToast("success", `Payment successful`);
sendMessage("pay-and-play-next", {
spaceId,
userId: user?.id,
url:inputLink
});
}
catch(error){
enqueueToast("error", `Payment unsuccessful`);
}
setLoading(false);

};

const videoId = inputLink ? inputLink.match(YT_REGEX)?.[1] : undefined;

return (
Expand All @@ -67,6 +129,18 @@ export default function AddSongForm({
>
{loading ? "Loading..." : "Add to Queue"}
</Button>

{ isSpectator &&
<Button
disabled={loading}
onClick={handlePayAndPlay}
type="submit"
className="w-full"
>
{loading ? "Loading..." : "Pay and Play"}
</Button>
}

</form>

{videoId && !loading && (
Expand Down
5 changes: 3 additions & 2 deletions next-app/components/StreamView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export default function StreamView({
return json.activeStream.stream;
});
setSpaceName(json.spaceName)

} catch (error) {
enqueueToast("error", "Something went wrong");
}
Expand Down Expand Up @@ -129,7 +130,7 @@ export default function StreamView({

return (
<div className="flex min-h-screen flex-col">
<Appbar />
<Appbar isSpectator={!playVideo}/>
<div className='mx-auto text-2xl bg-gradient-to-r rounded-lg from-indigo-600 to-violet-800 font-bold'>
{spaceName}
</div>
Expand All @@ -153,8 +154,8 @@ export default function StreamView({
setInputLink={setInputLink}
setLoading={setLoading}
spaceId={spaceId}
isSpectator={!playVideo}
/>

<NowPlaying
currentVideo={currentVideo}
playNext={playNext}
Expand Down
4 changes: 2 additions & 2 deletions next-app/components/auth/sign-in-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function SigninCard({ setFormType: setState }: SigninCardProps) {
email,
password,
redirect: false,
callbackUrl: "/",
callbackUrl: "/home",
});
res.then((res) => {
if (res?.error) {
Expand All @@ -44,7 +44,7 @@ export default function SigninCard({ setFormType: setState }: SigninCardProps) {
if (provider === "google") {
const res = signIn(provider, {
redirect: false,
callbackUrl: "/",
callbackUrl: "/home",
});
res.then((res) => {
if (res?.error) {
Expand Down
4 changes: 2 additions & 2 deletions next-app/components/auth/sign-up-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default function SignupCard({ setFormType: setState }: SignupCardProps) {
email,
password,
redirect: false,
callbackUrl: "/",
callbackUrl: "/home",
});
res.then((res) => {
if (res?.error) {
Expand All @@ -51,7 +51,7 @@ export default function SignupCard({ setFormType: setState }: SignupCardProps) {
if (provider === "google") {
const res = signIn(provider, {
redirect: false,
callbackUrl: "/",
callbackUrl: "/home",
});
res.then((res) => {
if (res?.error) {
Expand Down
14 changes: 11 additions & 3 deletions next-app/components/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
"use client";

import { SocketContextProvider } from "@/context/socket-context";
import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { SessionProvider } from "next-auth/react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { type ThemeProviderProps } from "next-themes/dist/types";

export function Providers({ children }: { children: React.ReactNode }) {
return (
<SessionProvider>
<SocketContextProvider>{children}</SocketContextProvider>
</SessionProvider>
<ConnectionProvider endpoint={"https://api.devnet.solana.com"}>
<WalletProvider wallets={[]} autoConnect>
<WalletModalProvider>
<SessionProvider>
<SocketContextProvider>{children}</SocketContextProvider>
</SessionProvider>
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
);
}

Expand Down
2 changes: 1 addition & 1 deletion next-app/hooks/useRedirect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export default function useRedirect() {
useEffect(() => {
if (session.status === "unauthenticated") {
router.push("/");
}
}
}, [session]);
}
21 changes: 21 additions & 0 deletions next-app/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { getToken } from "next-auth/jwt";

export default async function middleware(req: NextRequest) {
const token = await getToken({ req: req, secret: process.env.NEXTAUTH_SECRET });
const isAuthenticated = token ? true : false;
const pathSegments = req.nextUrl.pathname.split('/');


if (!isAuthenticated && (pathSegments[1] == 'home' || pathSegments[1] == 'dashboard' || pathSegments[1] == 'spaces')) {
const loginPath = `/auth`;
const loginURL = new URL(loginPath, req.nextUrl.origin);
return NextResponse.redirect(loginURL.toString());
}
if ((isAuthenticated && pathSegments[1] == "auth")) {
const newURL = new URL("/home", req.nextUrl.origin);
return NextResponse.redirect(newURL.toString());
}
return NextResponse.next();
}
5 changes: 5 additions & 0 deletions next-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@solana/wallet-adapter-base": "^0.9.23",
"@solana/wallet-adapter-react": "^0.15.35",
"@solana/wallet-adapter-react-ui": "^0.9.35",
"@solana/wallet-adapter-wallets": "^0.19.32",
"@solana/web3.js": "^1.95.3",
"axios": "^1.7.5",
"bcryptjs": "^2.4.3",
"class-variance-authority": "^0.7.0",
Expand Down
Loading

0 comments on commit 30dcf77

Please sign in to comment.