Merge pull request #399 from Monadical-SAS/fullscreen-rooms

Fullscreen rooms
This commit is contained in:
2024-09-02 15:43:48 +02:00
committed by GitHub
60 changed files with 686 additions and 579 deletions

118
www/app/(app)/layout.tsx Normal file
View File

@@ -0,0 +1,118 @@
import { Container, Flex, Link } from "@chakra-ui/layout";
import { getConfig } from "../lib/edgeConfig";
import NextLink from "next/link";
import Image from "next/image";
import About from "../(aboutAndPrivacy)/about";
import Privacy from "../(aboutAndPrivacy)/privacy";
import UserInfo from "../(auth)/userInfo";
export default async function AppLayout({
children,
}: {
children: React.ReactNode;
}) {
const config = await getConfig();
const { requireLogin, privacy, browse, rooms } = config.features;
return (
<Container
minW="100vw"
maxH="100vh"
minH="100vh"
maxW="container.xl"
display="grid"
gridTemplateRows="auto minmax(0,1fr)"
>
<Flex
as="header"
justify="space-between"
alignItems="center"
w="100%"
py="2"
px="0"
>
{/* Logo on the left */}
<Link
as={NextLink}
href="/"
className="flex outline-blue-300 md:outline-none focus-visible:underline underline-offset-2 decoration-[.5px] decoration-gray-500"
>
<Image
src="/reach.png"
width={16}
height={16}
className="h-10 w-auto"
alt="Reflector"
/>
<div className="hidden flex-col ml-2 md:block">
<h1 className="text-[38px] font-bold tracking-wide leading-tight">
Reflector
</h1>
<p className="text-gray-500 text-xs tracking-tighter">
Capture the signal, not the noise
</p>
</div>
</Link>
<div>
{/* Text link on the right */}
<Link
as={NextLink}
href="/transcripts/new"
className="hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
>
Create
</Link>
{browse ? (
<>
&nbsp;·&nbsp;
<Link
href="/browse"
as={NextLink}
className="hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
prefetch={false}
>
Browse
</Link>
</>
) : (
<></>
)}
{rooms ? (
<>
&nbsp;·&nbsp;
<Link
href="/rooms"
as={NextLink}
className="hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
prefetch={false}
>
Rooms
</Link>
</>
) : (
<></>
)}
&nbsp;·&nbsp;
<About buttonText="About" />
{privacy ? (
<>
&nbsp;·&nbsp;
<Privacy buttonText="Privacy" />
</>
) : (
<></>
)}
{requireLogin ? (
<>
&nbsp;·&nbsp;
<UserInfo />
</>
) : (
<></>
)}
</div>
</Flex>
{children}
</Container>
);
}

View File

@@ -35,7 +35,7 @@ import { Container } from "@chakra-ui/react";
import { FaEllipsisVertical, FaTrash, FaPencil } from "react-icons/fa6"; import { FaEllipsisVertical, FaTrash, FaPencil } from "react-icons/fa6";
import useApi from "../../lib/useApi"; import useApi from "../../lib/useApi";
import useRoomList from "./useRoomList"; import useRoomList from "./useRoomList";
import { DomainContext } from "../domainContext"; import { DomainContext } from "../../domainContext";
import { Select, Options, OptionBase } from "chakra-react-select"; import { Select, Options, OptionBase } from "chakra-react-select";
interface Stream { interface Stream {

View File

@@ -3,7 +3,7 @@ import SelectSearch from "react-select-search";
import { getZulipMessage, sendZulipMessage } from "../../../lib/zulip"; import { getZulipMessage, sendZulipMessage } from "../../../lib/zulip";
import { GetTranscript, GetTranscriptTopic } from "../../../api"; import { GetTranscript, GetTranscriptTopic } from "../../../api";
import "react-select-search/style.css"; import "react-select-search/style.css";
import { DomainContext } from "../../domainContext"; import { DomainContext } from "../../../domainContext";
type ShareModal = { type ShareModal = {
show: boolean; show: boolean;

View File

@@ -11,7 +11,7 @@ import useCreateTranscript from "../createTranscript";
import SelectSearch from "react-select-search"; import SelectSearch from "react-select-search";
import { supportedLanguages } from "../../../supportedLanguages"; import { supportedLanguages } from "../../../supportedLanguages";
import { useFiefIsAuthenticated } from "@fief/fief/nextjs/react"; import { useFiefIsAuthenticated } from "@fief/fief/nextjs/react";
import { featureEnabled } from "../../domainContext"; import { featureEnabled } from "../../../domainContext";
import { Button, Text } from "@chakra-ui/react"; import { Button, Text } from "@chakra-ui/react";
const TranscriptCreate = () => { const TranscriptCreate = () => {
const router = useRouter(); const router = useRouter();

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { featureEnabled } from "../domainContext"; import { featureEnabled } from "../../domainContext";
import { ShareMode, toShareMode } from "../../lib/shareMode"; import { ShareMode, toShareMode } from "../../lib/shareMode";
import { GetTranscript, GetTranscriptTopic, UpdateTranscript } from "../../api"; import { GetTranscript, GetTranscriptTopic, UpdateTranscript } from "../../api";

View File

@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect, use } from "react"; import React, { useState, useRef, useEffect, use } from "react";
import { featureEnabled } from "../domainContext"; import { featureEnabled } from "../../domainContext";
import { Button, Flex, Input, Text } from "@chakra-ui/react"; import { Button, Flex, Input, Text } from "@chakra-ui/react";
import QRCode from "react-qr-code"; import QRCode from "react-qr-code";

View File

@@ -1,5 +1,5 @@
import { useState } from "react"; import { useState } from "react";
import { featureEnabled } from "../domainContext"; import { featureEnabled } from "../../domainContext";
import ShareModal from "./[transcriptId]/shareModal"; import ShareModal from "./[transcriptId]/shareModal";
import { GetTranscript, GetTranscriptTopic } from "../../api"; import { GetTranscript, GetTranscriptTopic } from "../../api";
import { BoxProps, Button } from "@chakra-ui/react"; import { BoxProps, Button } from "@chakra-ui/react";

View File

@@ -14,7 +14,7 @@ import {
Flex, Flex,
Text, Text,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { featureEnabled } from "../domainContext"; import { featureEnabled } from "../../domainContext";
type TopicListProps = { type TopicListProps = {
topics: Topic[]; topics: Topic[];

View File

@@ -1,5 +1,5 @@
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import { DomainContext } from "../domainContext"; import { DomainContext } from "../../domainContext";
import getApi from "../../lib/useApi"; import getApi from "../../lib/useApi";
import { useFiefAccessTokenInfo } from "@fief/fief/build/esm/nextjs/react"; import { useFiefAccessTokenInfo } from "@fief/fief/build/esm/nextjs/react";

View File

@@ -1,7 +1,7 @@
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import { Topic, FinalSummary, Status } from "./webSocketTypes"; import { Topic, FinalSummary, Status } from "./webSocketTypes";
import { useError } from "../../(errors)/errorContext"; import { useError } from "../../(errors)/errorContext";
import { DomainContext } from "../domainContext"; import { DomainContext } from "../../domainContext";
import { AudioWaveform, GetTranscriptSegmentTopic } from "../../api"; import { AudioWaveform, GetTranscriptSegmentTopic } from "../../api";
import useApi from "../../lib/useApi"; import useApi from "../../lib/useApi";

View File

@@ -1,33 +0,0 @@
"use client";
import "@whereby.com/browser-sdk/embed";
import { useRef } from "react";
import useRoomMeeting from "./useRoomMeeting";
export type RoomDetails = {
params: {
roomName: string;
};
};
export default function Room(details: RoomDetails) {
const wherebyRef = useRef<HTMLElement>(null);
const roomName = details.params.roomName;
const meeting = useRoomMeeting(roomName);
const roomUrl = meeting?.response?.host_room_url
? meeting?.response?.host_room_url
: meeting?.response?.room_url;
return (
<>
{roomUrl && (
<whereby-embed
ref={wherebyRef}
room={roomUrl}
style={{ width: "100%", height: "98%" }}
/>
)}
</>
);
}

View File

@@ -1,203 +0,0 @@
import "../styles/globals.scss";
import { Poppins } from "next/font/google";
import { Metadata, Viewport } from "next";
import FiefWrapper from "../(auth)/fiefWrapper";
import UserInfo from "../(auth)/userInfo";
import { ErrorProvider } from "../(errors)/errorContext";
import ErrorMessage from "../(errors)/errorMessage";
import Image from "next/image";
import About from "../(aboutAndPrivacy)/about";
import Privacy from "../(aboutAndPrivacy)/privacy";
import { DomainContextProvider } from "./domainContext";
import { getConfig } from "../lib/edgeConfig";
import { ErrorBoundary } from "@sentry/nextjs";
import { cookies } from "next/dist/client/components/headers";
import { SESSION_COOKIE_NAME } from "../lib/fief";
import { Providers } from "../providers";
import NextLink from "next/link";
import { Container, Flex, Link } from "@chakra-ui/react";
const poppins = Poppins({ subsets: ["latin"], weight: ["200", "400", "600"] });
export const viewport: Viewport = {
themeColor: "black",
width: "device-width",
initialScale: 1,
maximumScale: 1,
};
export const metadata: Metadata = {
metadataBase: new URL(process.env.DEV_URL || "https://reflector.media"),
title: {
template: "%s Reflector",
default: "Reflector - AI-Powered Meeting Transcriptions by Monadical",
},
description:
"Reflector is an AI-powered tool that transcribes your meetings with unparalleled accuracy, divides content by topics, and provides insightful summaries. Maximize your productivity with Reflector, brought to you by Monadical. Capture the signal, not the noise",
applicationName: "Reflector",
referrer: "origin-when-cross-origin",
keywords: ["Reflector", "Monadical", "AI", "Meetings", "Transcription"],
authors: [{ name: "Monadical Team", url: "https://monadical.com/team.html" }],
formatDetection: {
email: false,
address: false,
telephone: false,
},
openGraph: {
title: "Reflector",
description:
"Reflector is an AI-powered tool that transcribes your meetings with unparalleled accuracy, divides content by topics, and provides insightful summaries. Maximize your productivity with Reflector, brought to you by Monadical. Capture the signal, not the noise.",
type: "website",
},
twitter: {
card: "summary_large_image",
title: "Reflector",
description:
"Reflector is an AI-powered tool that transcribes your meetings with unparalleled accuracy, divides content by topics, and provides insightful summaries. Maximize your productivity with Reflector, brought to you by Monadical. Capture the signal, not the noise.",
images: ["/r-icon.png"],
},
icons: {
icon: "/r-icon.png",
shortcut: "/r-icon.png",
apple: "/r-icon.png",
},
robots: { index: false, follow: false, noarchive: true, noimageindex: true },
};
type LayoutProps = {
params: {
domain: string;
};
children: any;
};
export default async function RootLayout({ children, params }: LayoutProps) {
const config = await getConfig(params.domain);
const { requireLogin, privacy, browse, rooms } = config.features;
const hasAuthCookie = !!cookies().get(SESSION_COOKIE_NAME);
return (
<html lang="en">
<body
className={
poppins.className + "h-[100svh] w-[100svw] overflow-hidden relative"
}
>
<FiefWrapper hasAuthCookie={hasAuthCookie}>
<DomainContextProvider config={config}>
<ErrorBoundary fallback={<p>"something went really wrong"</p>}>
<ErrorProvider>
<ErrorMessage />
<Providers>
<Container
minW="100vw"
maxH="100vh"
minH="100vh"
maxW="container.xl"
display="grid"
gridTemplateRows="auto minmax(0,1fr)"
>
<Flex
as="header"
justify="space-between"
alignItems="center"
w="100%"
py="2"
px="0"
>
{/* Logo on the left */}
<Link
as={NextLink}
href="/"
className="flex outline-blue-300 md:outline-none focus-visible:underline underline-offset-2 decoration-[.5px] decoration-gray-500"
>
<Image
src="/reach.png"
width={16}
height={16}
className="h-10 w-auto"
alt="Reflector"
/>
<div className="hidden flex-col ml-2 md:block">
<h1 className="text-[38px] font-bold tracking-wide leading-tight">
Reflector
</h1>
<p className="text-gray-500 text-xs tracking-tighter">
Capture the signal, not the noise
</p>
</div>
</Link>
<div>
{/* Text link on the right */}
<Link
as={NextLink}
href="/transcripts/new"
className="hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
>
Create
</Link>
{browse ? (
<>
&nbsp;·&nbsp;
<Link
href="/browse"
as={NextLink}
className="hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
prefetch={false}
>
Browse
</Link>
</>
) : (
<></>
)}
{rooms ? (
<>
&nbsp;·&nbsp;
<Link
href="/rooms"
as={NextLink}
className="hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
prefetch={false}
>
Rooms
</Link>
</>
) : (
<></>
)}
&nbsp;·&nbsp;
<About buttonText="About" />
{privacy ? (
<>
&nbsp;·&nbsp;
<Privacy buttonText="Privacy" />
</>
) : (
<></>
)}
{requireLogin ? (
<>
&nbsp;·&nbsp;
<UserInfo />
</>
) : (
<></>
)}
</div>
</Flex>
{children}
</Container>
</Providers>
</ErrorProvider>
</ErrorBoundary>
</DomainContextProvider>
</FiefWrapper>
</body>
</html>
);
}

View File

@@ -0,0 +1,51 @@
"use client";
import "@whereby.com/browser-sdk/embed";
import { useCallback, useEffect, useRef } from "react";
import useRoomMeeting from "./useRoomMeeting";
import { useRouter } from "next/navigation";
import { useFiefIsAuthenticated } from "@fief/fief/build/esm/nextjs/react";
export type RoomDetails = {
params: {
roomName: string;
};
};
export default function Room(details: RoomDetails) {
const wherebyRef = useRef<HTMLElement>(null);
const roomName = details.params.roomName;
const meeting = useRoomMeeting(roomName);
const router = useRouter();
const isAuthenticated = useFiefIsAuthenticated();
const roomUrl = meeting?.response?.host_room_url
? meeting?.response?.host_room_url
: meeting?.response?.room_url;
const handleLeave = useCallback((e) => {
router.push("/browse");
}, []);
useEffect(() => {
if (!isAuthenticated || !roomUrl) return;
wherebyRef.current?.addEventListener("leave", handleLeave);
return () => {
wherebyRef.current?.removeEventListener("leave", handleLeave);
};
}, [handleLeave, roomUrl]);
return (
<>
{roomUrl && (
<whereby-embed
ref={wherebyRef}
room={roomUrl}
style={{ width: "100vw", height: "100vh" }}
/>
)}
</>
);
}

View File

@@ -1,8 +1,8 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useError } from "../../(errors)/errorContext"; import { useError } from "../(errors)/errorContext";
import { Meeting } from "../../api"; import { Meeting } from "../api";
import { shouldShowError } from "../../lib/errorUtils"; import { shouldShowError } from "../lib/errorUtils";
import useApi from "../../lib/useApi"; import useApi from "../lib/useApi";
type ErrorMeeting = { type ErrorMeeting = {
error: Error; error: Error;

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { createContext, useContext, useEffect, useState } from "react"; import { createContext, useContext, useEffect, useState } from "react";
import { DomainConfig } from "../lib/edgeConfig"; import { DomainConfig } from "./lib/edgeConfig";
type DomainContextType = Omit<DomainConfig, "auth_callback_url">; type DomainContextType = Omit<DomainConfig, "auth_callback_url">;

92
www/app/layout.tsx Normal file
View File

@@ -0,0 +1,92 @@
import "./styles/globals.scss";
import { Poppins } from "next/font/google";
import { Metadata, Viewport } from "next";
import FiefWrapper from "./(auth)/fiefWrapper";
import { ErrorProvider } from "./(errors)/errorContext";
import ErrorMessage from "./(errors)/errorMessage";
import { DomainContextProvider } from "./domainContext";
import { getConfig } from "./lib/edgeConfig";
import { ErrorBoundary } from "@sentry/nextjs";
import { cookies } from "next/dist/client/components/headers";
import { SESSION_COOKIE_NAME } from "./lib/fief";
import { Providers } from "./providers";
const poppins = Poppins({ subsets: ["latin"], weight: ["200", "400", "600"] });
export const viewport: Viewport = {
themeColor: "black",
width: "device-width",
initialScale: 1,
maximumScale: 1,
};
export const metadata: Metadata = {
metadataBase: new URL(process.env.DEV_URL || "https://reflector.media"),
title: {
template: "%s Reflector",
default: "Reflector - AI-Powered Meeting Transcriptions by Monadical",
},
description:
"Reflector is an AI-powered tool that transcribes your meetings with unparalleled accuracy, divides content by topics, and provides insightful summaries. Maximize your productivity with Reflector, brought to you by Monadical. Capture the signal, not the noise",
applicationName: "Reflector",
referrer: "origin-when-cross-origin",
keywords: ["Reflector", "Monadical", "AI", "Meetings", "Transcription"],
authors: [{ name: "Monadical Team", url: "https://monadical.com/team.html" }],
formatDetection: {
email: false,
address: false,
telephone: false,
},
openGraph: {
title: "Reflector",
description:
"Reflector is an AI-powered tool that transcribes your meetings with unparalleled accuracy, divides content by topics, and provides insightful summaries. Maximize your productivity with Reflector, brought to you by Monadical. Capture the signal, not the noise.",
type: "website",
},
twitter: {
card: "summary_large_image",
title: "Reflector",
description:
"Reflector is an AI-powered tool that transcribes your meetings with unparalleled accuracy, divides content by topics, and provides insightful summaries. Maximize your productivity with Reflector, brought to you by Monadical. Capture the signal, not the noise.",
images: ["/r-icon.png"],
},
icons: {
icon: "/r-icon.png",
shortcut: "/r-icon.png",
apple: "/r-icon.png",
},
robots: { index: false, follow: false, noarchive: true, noimageindex: true },
};
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const config = await getConfig();
const hasAuthCookie = !!cookies().get(SESSION_COOKIE_NAME);
return (
<html lang="en">
<body
className={
poppins.className + "h-[100svh] w-[100svw] overflow-hidden relative"
}
>
<FiefWrapper hasAuthCookie={hasAuthCookie}>
<DomainContextProvider config={config}>
<ErrorBoundary fallback={<p>"something went really wrong"</p>}>
<ErrorProvider>
<ErrorMessage />
<Providers>{children}</Providers>
</ErrorProvider>
</ErrorBoundary>
</DomainContextProvider>
</FiefWrapper>
</body>
</html>
);
}

View File

@@ -29,7 +29,9 @@ export function edgeDomainToKey(domain: string) {
} }
// get edge config server-side (prefer DomainContext when available), domain is the hostname // get edge config server-side (prefer DomainContext when available), domain is the hostname
export async function getConfig(domain: string) { export async function getConfig() {
const domain = new URL(process.env.NEXT_PUBLIC_SITE_URL!).hostname;
if (process.env.NEXT_PUBLIC_ENV === "development") { if (process.env.NEXT_PUBLIC_ENV === "development") {
return require("../../config").localConfig; return require("../../config").localConfig;
} }

View File

@@ -44,7 +44,7 @@ export const getFiefAuth = async (url: URL) => {
if (FIEF_AUTHS[url.hostname]) { if (FIEF_AUTHS[url.hostname]) {
return FIEF_AUTHS[url.hostname]; return FIEF_AUTHS[url.hostname];
} else { } else {
const config = url && (await getConfig(url.hostname)); const config = url && (await getConfig());
if (config) { if (config) {
FIEF_AUTHS[url.hostname] = new FiefAuth({ FIEF_AUTHS[url.hostname] = new FiefAuth({
client: fiefClient, client: fiefClient,

View File

@@ -1,6 +1,6 @@
import { useFiefAccessTokenInfo } from "@fief/fief/nextjs/react"; import { useFiefAccessTokenInfo } from "@fief/fief/nextjs/react";
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import { DomainContext, featureEnabled } from "../[domain]/domainContext"; import { DomainContext, featureEnabled } from "../domainContext";
import { CookieContext } from "../(auth)/fiefWrapper"; import { CookieContext } from "../(auth)/fiefWrapper";
import { OpenApi, DefaultService } from "../api"; import { OpenApi, DefaultService } from "../api";

View File

@@ -4,8 +4,7 @@ import { getFiefAuthMiddleware } from "./app/lib/fief";
import { getConfig } from "./app/lib/edgeConfig"; import { getConfig } from "./app/lib/edgeConfig";
export async function middleware(request: NextRequest) { export async function middleware(request: NextRequest) {
const domain = request.nextUrl.hostname; const config = await getConfig();
const config = await getConfig(domain);
if ( if (
request.nextUrl.pathname.match( request.nextUrl.pathname.match(
@@ -24,25 +23,8 @@ export async function middleware(request: NextRequest) {
if (config.features.requireLogin) { if (config.features.requireLogin) {
const fiefMiddleware = await getFiefAuthMiddleware(request.nextUrl); const fiefMiddleware = await getFiefAuthMiddleware(request.nextUrl);
const fiefResponse = await fiefMiddleware(request); const fiefResponse = await fiefMiddleware(request);
if (!fiefResponse.headers.get("x-middleware-rewrite")) {
fiefResponse.headers.set(
"x-middleware-rewrite",
request.nextUrl.origin + "/" + domain + request.nextUrl.pathname,
);
}
return fiefResponse; return fiefResponse;
} }
if (
request.nextUrl.pathname == "/" ||
request.nextUrl.pathname.startsWith("/transcripts") ||
request.nextUrl.pathname.startsWith("/browse") ||
request.nextUrl.pathname.startsWith("/rooms")
) {
return NextResponse.rewrite(
request.nextUrl.origin + "/" + domain + request.nextUrl.pathname,
);
}
} }
return NextResponse.next(); return NextResponse.next();

View File

@@ -11,9 +11,15 @@
"openapi": "openapi-ts" "openapi": "openapi-ts"
}, },
"dependencies": { "dependencies": {
"@chakra-ui/icons": "^2.1.1", "@chakra-ui/icons": "2.1.1",
"@chakra-ui/icon": "3.2.0",
"@chakra-ui/system": "2.6.2",
"@chakra-ui/menu": "^2.2.1", "@chakra-ui/menu": "^2.2.1",
"@chakra-ui/next-js": "^2.2.0", "@chakra-ui/next-js": "^2.2.0",
"@chakra-ui/layout": "^2.3.1",
"@chakra-ui/media-query": "^3.3.0",
"@chakra-ui/spinner": "^2.1.0",
"@chakra-ui/form-control": "2.2.0",
"@chakra-ui/react": "^2.8.2", "@chakra-ui/react": "^2.8.2",
"@chakra-ui/react-types": "^2.0.6", "@chakra-ui/react-types": "^2.0.6",
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
@@ -25,15 +31,15 @@
"@sentry/nextjs": "^7.77.0", "@sentry/nextjs": "^7.77.0",
"@vercel/edge-config": "^0.4.1", "@vercel/edge-config": "^0.4.1",
"@whereby.com/browser-sdk": "^3.3.4", "@whereby.com/browser-sdk": "^3.3.4",
"autoprefixer": "10.4.14", "autoprefixer": "10.4.20",
"axios": "^1.6.2", "axios": "^1.6.2",
"chakra-react-select": "^4.9.1", "chakra-react-select": "^4.9.1",
"eslint": "^8.56.0", "eslint": "^9.9.1",
"eslint-config-next": "^14.0.4", "eslint-config-next": "^14.2.7",
"fontawesome": "^5.6.3", "fontawesome": "^5.6.3",
"framer-motion": "^10.16.16", "framer-motion": "^10.16.16",
"jest-worker": "^29.6.2", "jest-worker": "^29.6.2",
"next": "^14.0.4", "next": "^14.2.7",
"postcss": "8.4.25", "postcss": "8.4.25",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.2.0", "react": "^18.2.0",

View File

@@ -3,9 +3,8 @@ import { URLSearchParams } from "url";
import { getConfig } from "../../app/lib/edgeConfig"; import { getConfig } from "../../app/lib/edgeConfig";
export default async function handler(req, res) { export default async function handler(req, res) {
const domainName = req.headers.host; const config = await getConfig();
const config = await getConfig(domainName); const { sendToZulip } = config.features;
const { requireLogin, privacy, browse, sendToZulip } = config.features;
if (req.method === "POST") { if (req.method === "POST") {
const { stream, topic, message } = req.body; const { stream, topic, message } = req.body;

File diff suppressed because it is too large Load Diff