From 3f4fe9cec0339a85119c43a6f745301a8edac1d3 Mon Sep 17 00:00:00 2001 From: vrajdesai78 Date: Mon, 8 Jan 2024 18:05:57 +0530 Subject: [PATCH 1/2] Improved joining flow --- src/app/api/room/route.ts | 2 +- src/app/page.tsx | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/app/api/room/route.ts b/src/app/api/room/route.ts index c55b64c..10dac89 100644 --- a/src/app/api/room/route.ts +++ b/src/app/api/room/route.ts @@ -6,7 +6,7 @@ class Huddle01CreateRoomError extends Error { } } -export async function GET(request: Request) { +export async function GET() { const API_KEY = process.env.HUDDLE_API_KEY; if (!API_KEY) { diff --git a/src/app/page.tsx b/src/app/page.tsx index 8e6bed4..c388e14 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -8,6 +8,14 @@ export default function Home() { const [roomId, setRoomId] = useState(""); const router = useRouter(); + const createRoom = async () => { + const res = await fetch("/api/room"); + const data = await res.json(); + if (data.roomId) { + router.push(`/${data.roomId}`); + } + }; + return (
@@ -29,6 +37,13 @@ export default function Home() { > Start Meeting +
); From 2da91335637ab6d2eb7e7b527cdd67935c58048e Mon Sep 17 00:00:00 2001 From: vrajdesai78 Date: Tue, 7 May 2024 21:41:00 +0530 Subject: [PATCH 2/2] added token creation --- package.json | 2 + pnpm-lock.yaml | 85 +++++++++++++++++++ src/app/[roomId]/page.tsx | 20 +++-- src/app/api/room/route.ts | 2 +- src/app/api/token/route.ts | 48 +++++++++++ src/app/components/Customize/Customize.tsx | 22 ++--- .../components/Customize/Inputs/Inputs.tsx | 50 ++++++----- .../components/Customize/Themes/Themes.tsx | 1 + src/app/components/createToken.ts | 27 ++++++ src/app/page.tsx | 18 ++-- 10 files changed, 226 insertions(+), 49 deletions(-) create mode 100644 src/app/api/token/route.ts create mode 100644 src/app/components/createToken.ts diff --git a/package.json b/package.json index f5322ec..ca5933b 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@huddle01/iframe": "0.0.12", + "@huddle01/server-sdk": "^2.0.5", "@types/node": "20.1.4", "@types/react": "18.2.6", "@types/react-dom": "18.2.4", @@ -22,6 +23,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "tailwindcss": "3.3.2", + "types": "link:@huddle01/iframe/types", "typescript": "5.0.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7c4efc9..756beaa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ dependencies: '@huddle01/iframe': specifier: 0.0.12 version: 0.0.12(react@18.2.0) + '@huddle01/server-sdk': + specifier: ^2.0.5 + version: 2.0.5 '@types/node': specifier: 20.1.4 version: 20.1.4 @@ -44,6 +47,9 @@ dependencies: tailwindcss: specifier: 3.3.2 version: 3.3.2 + types: + specifier: link:@huddle01/iframe/types + version: link:@huddle01/iframe/types typescript: specifier: 5.0.4 version: 5.0.4 @@ -108,6 +114,16 @@ packages: zod: 3.21.4 dev: false + /@huddle01/server-sdk@2.0.5: + resolution: {integrity: sha512-WGfsZgTjKlEYw1V/fQmsJ646Y9UaEYE0zvRXX4kaXKcp7yFXuQ7Tih+F9wjGQfplORkTVeH1lbBIp1xGc+Dhlg==} + dependencies: + axios: 1.6.7 + jose: 4.15.4 + zod: 3.22.4 + transitivePeerDependencies: + - debug + dev: false + /@humanwhocodes/config-array@0.11.8: resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} engines: {node: '>=10.10.0'} @@ -506,6 +522,10 @@ packages: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} dev: false + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + /autoprefixer@10.4.14(postcss@8.4.23): resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} engines: {node: ^10 || ^12 || >=14} @@ -532,6 +552,16 @@ packages: engines: {node: '>=4'} dev: false + /axios@1.6.7: + resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} + dependencies: + follow-redirects: 1.15.5 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + /axobject-query@3.1.1: resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==} dependencies: @@ -662,6 +692,13 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: false + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -775,6 +812,11 @@ packages: object-keys: 1.1.1 dev: false + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} dev: false @@ -1276,12 +1318,31 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: false + /follow-redirects@1.15.5: + resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 dev: false + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /fraction.js@4.2.0: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} dev: false @@ -1730,6 +1791,10 @@ packages: hasBin: true dev: false + /jose@4.15.4: + resolution: {integrity: sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==} + dev: false + /js-sdsl@4.4.0: resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==} dev: false @@ -1837,6 +1902,18 @@ packages: picomatch: 2.3.1 dev: false + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -2230,6 +2307,10 @@ packages: react-is: 16.13.1 dev: false + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} @@ -2751,3 +2832,7 @@ packages: /zod@3.21.4: resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} dev: false + + /zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + dev: false diff --git a/src/app/[roomId]/page.tsx b/src/app/[roomId]/page.tsx index a523b34..35fbcd3 100644 --- a/src/app/[roomId]/page.tsx +++ b/src/app/[roomId]/page.tsx @@ -7,7 +7,7 @@ import HuddleLogo from "../components/HuddleLogo"; import DocBtn from "../components/DocBtn"; import { usePathname, useSearchParams } from "next/navigation"; -import { useEffect, useState } from "react"; +import { useState } from "react"; export default function Home({ params }: { params: { roomId: string } }) { const [isDark, setIsDark] = useState(true); @@ -40,20 +40,24 @@ export default function Home({ params }: { params: { roomId: string } }) { }); return ( -
-
+
+
-
- -
+
+ +
diff --git a/src/app/api/room/route.ts b/src/app/api/room/route.ts index 10dac89..4ccb6bf 100644 --- a/src/app/api/room/route.ts +++ b/src/app/api/room/route.ts @@ -22,7 +22,7 @@ export async function GET() { } try { const response = await fetch( - "https://api.huddle01.com/api/v1/create-iframe-room", + "https://api.huddle01.com/api/v1/create-room", { method: "POST", body: JSON.stringify({ diff --git a/src/app/api/token/route.ts b/src/app/api/token/route.ts new file mode 100644 index 0000000..a2dc6ae --- /dev/null +++ b/src/app/api/token/route.ts @@ -0,0 +1,48 @@ +import { AccessToken, Role } from '@huddle01/server-sdk/auth'; + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url); + + const roomId = searchParams.get('roomId'); + const walletAddress = searchParams.get('walletAddress'); + + console.log({ roomId, walletAddress }); + + if (!roomId) { + return new Response('Missing roomId', { status: 400 }); + } + + console.log('HUDDLE_API_KEY', process.env.HUDDLE_API_KEY); + + const accessToken = new AccessToken({ + apiKey: process.env.HUDDLE_API_KEY as string, + roomId: roomId as string, + role: Role.HOST, + permissions: { + admin: true, + canConsume: true, + canProduce: true, + canProduceSources: { + cam: true, + mic: true, + screen: true, + }, + canRecvData: true, + canSendData: true, + canUpdateMetadata: true, + }, + options: { + metadata: { + walletAddress, + }, + }, + }); + + const token = await accessToken.toJwt(); + + console.log({ token }); + + return new Response(token, { + status: 200, + }); +} diff --git a/src/app/components/Customize/Customize.tsx b/src/app/components/Customize/Customize.tsx index 28235e5..5968c44 100644 --- a/src/app/components/Customize/Customize.tsx +++ b/src/app/components/Customize/Customize.tsx @@ -1,22 +1,22 @@ -import React, { Dispatch, SetStateAction } from "react"; -import Essentials from "./Essentials/Essentials"; -import Inputs from "./Inputs/Inputs"; -import Wallets from "./Wallets/Wallets"; +import React, { Dispatch, SetStateAction } from 'react'; +import Essentials from './Essentials/Essentials'; +import Inputs from './Inputs/Inputs'; +import Wallets from './Wallets/Wallets'; // import Additional from "./Additional/Additional"; -import Themes, { Props } from "./Themes/Themes"; +import Themes, { Props } from './Themes/Themes'; -const Customize = ({ isDark, setIsDark }: Props) => { +const Customize = ({ isDark, setIsDark, roomId }: Props) => { return ( -
-
-
Customize
+
+
+
Customize
{/*
Reset
*/}
- + {/* */} - +
); }; diff --git a/src/app/components/Customize/Inputs/Inputs.tsx b/src/app/components/Customize/Inputs/Inputs.tsx index 4da4ac3..6bb2970 100644 --- a/src/app/components/Customize/Inputs/Inputs.tsx +++ b/src/app/components/Customize/Inputs/Inputs.tsx @@ -1,28 +1,30 @@ -import React, { useState } from "react"; -import Section from "../Section/Section"; -import TextInputWithBtn from "./TextInputWithBtn/TextInputWithBtn"; -import Select from "./TextInputWithBtn/Select"; -import { TReaction, reactions } from "@huddle01/iframe/types"; -import Button from "./TextInputWithBtn/Button"; -import { iframeApi, useEventListener } from "@huddle01/iframe"; +import React, { useState } from 'react'; +import Section from '../Section/Section'; +import TextInputWithBtn from './TextInputWithBtn/TextInputWithBtn'; +import Select from './TextInputWithBtn/Select'; +import { TReaction, reactions } from '@huddle01/iframe/types'; +import Button from './TextInputWithBtn/Button'; +import { iframeApi, useEventListener } from '@huddle01/iframe'; +import { createToken } from '../../createToken'; -function Inputs() { +function Inputs({ roomId }: { roomId: string }) { const [isRoomJoined, setIsRoomJoined] = useState(false); const [inputs, setInputs] = useState({ - redirectURLOnLeave: "", - backgroundURL: "", - avatarURL: "", - logoURL: "", + redirectURLOnLeave: '', + backgroundURL: '', + avatarURL: '', + logoURL: '', + walletAddress: '', }); const keys = { - redirectURLOnLeave: "redirectUrlOnLeave", - backgroundURL: "background", - logoURL: "logoUrl", + redirectURLOnLeave: 'redirectUrlOnLeave', + backgroundURL: 'background', + logoURL: 'logoUrl', }; - const [reaction, setReaction] = useState("🎉"); + const [reaction, setReaction] = useState('🎉'); const onTextChange = (e: React.ChangeEvent) => setInputs((prev) => ({ ...prev, [e.target.name]: e.target.value })); @@ -30,12 +32,12 @@ function Inputs() { const onReactionChange = (e: React.ChangeEvent) => setReaction(e.target.value as TReaction); - useEventListener("room:joined", () => { + useEventListener('room:joined', () => { setIsRoomJoined(true); }); return ( -
+
{Object.keys(inputs).map((key) => ( { - if (key === "avatarURL") { + onClick={async () => { + if (key === 'avatarURL') { return iframeApi.changeAvatarUrl(inputs.avatarURL); } + if (key === 'walletAddress') { + const token = await createToken(roomId, inputs.walletAddress); + console.log('token', token); + return iframeApi.connectWallet(token); + } + iframeApi.initialize({ [keys[key as keyof typeof keys]]: inputs[key as keyof typeof inputs], @@ -56,7 +64,7 @@ function Inputs() { /> ))} -
+
setRoomId(e.target.value)} />