mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 12:19:06 +00:00
Auth front-end
This commit is contained in:
43
www/app/(auth)/userInfo.tsx
Normal file
43
www/app/(auth)/userInfo.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
"use client";
|
||||||
|
import {
|
||||||
|
useFiefIsAuthenticated,
|
||||||
|
useFiefUserinfo,
|
||||||
|
} from "@fief/fief/nextjs/react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
export default function UserInfo() {
|
||||||
|
const isAuthenticated = useFiefIsAuthenticated();
|
||||||
|
const userinfo = useFiefUserinfo();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header className="bg-black w-full border-b border-gray-700 flex justify-between items-center py-2 mb-3">
|
||||||
|
{/* Logo on the left */}
|
||||||
|
<Link href="/">
|
||||||
|
<Image
|
||||||
|
src="/reach.png"
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
className="h-6 w-auto ml-2"
|
||||||
|
alt="Reflector"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Text link on the right */}
|
||||||
|
{!isAuthenticated && (
|
||||||
|
<span className="text-white hover:underline font-thin px-2">
|
||||||
|
<Link href="/login">Log in or create account</Link>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{isAuthenticated && (
|
||||||
|
<span className="text-white font-thin px-2">
|
||||||
|
{userinfo?.email} (
|
||||||
|
<span className="hover:underline">
|
||||||
|
<Link href="/logout">Log out</Link>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ models/PageGetTranscript.ts
|
|||||||
models/RtcOffer.ts
|
models/RtcOffer.ts
|
||||||
models/TranscriptTopic.ts
|
models/TranscriptTopic.ts
|
||||||
models/UpdateTranscript.ts
|
models/UpdateTranscript.ts
|
||||||
|
models/UserInfo.ts
|
||||||
models/ValidationError.ts
|
models/ValidationError.ts
|
||||||
models/index.ts
|
models/index.ts
|
||||||
runtime.ts
|
runtime.ts
|
||||||
|
|||||||
@@ -742,4 +742,49 @@ export class DefaultApi extends runtime.BaseAPI {
|
|||||||
);
|
);
|
||||||
return await response.value();
|
return await response.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Me
|
||||||
|
*/
|
||||||
|
async v1UserMeRaw(
|
||||||
|
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||||
|
): Promise<runtime.ApiResponse<any>> {
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
if (this.configuration && this.configuration.accessToken) {
|
||||||
|
// oauth required
|
||||||
|
headerParameters["Authorization"] = await this.configuration.accessToken(
|
||||||
|
"OAuth2AuthorizationCodeBearer",
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.request(
|
||||||
|
{
|
||||||
|
path: `/v1/me`,
|
||||||
|
method: "GET",
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
},
|
||||||
|
initOverrides,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.isJsonMime(response.headers.get("content-type"))) {
|
||||||
|
return new runtime.JSONApiResponse<any>(response);
|
||||||
|
} else {
|
||||||
|
return new runtime.TextApiResponse(response) as any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Me
|
||||||
|
*/
|
||||||
|
async v1UserMe(
|
||||||
|
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||||
|
): Promise<any> {
|
||||||
|
const response = await this.v1UserMeRaw(initOverrides);
|
||||||
|
return await response.value();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
84
www/app/api/models/UserInfo.ts
Normal file
84
www/app/api/models/UserInfo.ts
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* FastAPI
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from "../runtime";
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface UserInfo
|
||||||
|
*/
|
||||||
|
export interface UserInfo {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {any}
|
||||||
|
* @memberof UserInfo
|
||||||
|
*/
|
||||||
|
sub: any | null;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {any}
|
||||||
|
* @memberof UserInfo
|
||||||
|
*/
|
||||||
|
email: any | null;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {any}
|
||||||
|
* @memberof UserInfo
|
||||||
|
*/
|
||||||
|
emailVerified: any | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the UserInfo interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfUserInfo(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
isInstance = isInstance && "sub" in value;
|
||||||
|
isInstance = isInstance && "email" in value;
|
||||||
|
isInstance = isInstance && "emailVerified" in value;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserInfoFromJSON(json: any): UserInfo {
|
||||||
|
return UserInfoFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserInfoFromJSONTyped(
|
||||||
|
json: any,
|
||||||
|
ignoreDiscriminator: boolean,
|
||||||
|
): UserInfo {
|
||||||
|
if (json === undefined || json === null) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
sub: json["sub"],
|
||||||
|
email: json["email"],
|
||||||
|
emailVerified: json["email_verified"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserInfoToJSON(value?: UserInfo | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
sub: value.sub,
|
||||||
|
email: value.email,
|
||||||
|
email_verified: value.emailVerified,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -8,4 +8,5 @@ export * from "./PageGetTranscript";
|
|||||||
export * from "./RtcOffer";
|
export * from "./RtcOffer";
|
||||||
export * from "./TranscriptTopic";
|
export * from "./TranscriptTopic";
|
||||||
export * from "./UpdateTranscript";
|
export * from "./UpdateTranscript";
|
||||||
|
export * from "./UserInfo";
|
||||||
export * from "./ValidationError";
|
export * from "./ValidationError";
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import "./styles/globals.scss";
|
import "./styles/globals.scss";
|
||||||
import { Roboto } from "next/font/google";
|
import { Roboto } from "next/font/google";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import FiefWrapper from "./fiefWrapper";
|
import FiefWrapper from "./(auth)/fiefWrapper";
|
||||||
import UserInfo from "./userInfo";
|
import UserInfo from "./(auth)/userInfo";
|
||||||
|
|
||||||
const roboto = Roboto({ subsets: ["latin"], weight: "400" });
|
const roboto = Roboto({ subsets: ["latin"], weight: "400" });
|
||||||
|
|
||||||
@@ -55,8 +55,19 @@ export default function RootLayout({ children }) {
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body className={roboto.className + " flex flex-col min-h-screen"}>
|
<body className={roboto.className + " flex flex-col min-h-screen"}>
|
||||||
<FiefWrapper>
|
<FiefWrapper>
|
||||||
<UserInfo />
|
<div id="container">
|
||||||
{children}
|
<div className="flex flex-col items-center h-[100svh] bg-gradient-to-r from-[#8ec5fc30] to-[#e0c3fc42]">
|
||||||
|
<UserInfo />
|
||||||
|
|
||||||
|
<div className="h-[13svh] flex flex-col justify-center items-center">
|
||||||
|
<h1 className="text-5xl font-bold text-blue-500">Reflector</h1>
|
||||||
|
<p className="text-gray-500">
|
||||||
|
Capture The Signal, Not The Noise
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</FiefWrapper>
|
</FiefWrapper>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
18
www/app/lib/getApi.ts
Normal file
18
www/app/lib/getApi.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Configuration } from "../api/runtime";
|
||||||
|
import { DefaultApi } from "../api/apis/DefaultApi";
|
||||||
|
|
||||||
|
import { useFiefAccessTokenInfo } from "@fief/fief/nextjs/react";
|
||||||
|
|
||||||
|
export default function getApi(): DefaultApi {
|
||||||
|
const accessTokenInfo = useFiefAccessTokenInfo();
|
||||||
|
|
||||||
|
const apiConfiguration = new Configuration({
|
||||||
|
basePath: process.env.NEXT_PUBLIC_API_URL,
|
||||||
|
accessToken: accessTokenInfo
|
||||||
|
? "Bearer " + accessTokenInfo.access_token
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
const api = new DefaultApi(apiConfiguration);
|
||||||
|
|
||||||
|
return api;
|
||||||
|
}
|
||||||
21
www/app/lib/user.ts
Normal file
21
www/app/lib/user.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export async function getCurrentUser(): Promise<any> {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/current-user");
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
// Ensure the data structure is as expected
|
||||||
|
if (data.userinfo && data.access_token_info) {
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
throw new Error("Unexpected data structure");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching the user data:", error);
|
||||||
|
throw error; // or you can return an appropriate fallback or error indicator
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,12 +26,7 @@ const App = () => {
|
|||||||
const webSockets = useWebSockets(transcript.response?.id);
|
const webSockets = useWebSockets(transcript.response?.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center h-[100svh] bg-gradient-to-r from-[#8ec5fc30] to-[#e0c3fc42]">
|
<>
|
||||||
<div className="h-[13svh] flex flex-col justify-center items-center">
|
|
||||||
<h1 className="text-5xl font-bold text-blue-500">Reflector</h1>
|
|
||||||
<p className="text-gray-500">Capture The Signal, Not The Noise</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Recorder
|
<Recorder
|
||||||
setStream={setStream}
|
setStream={setStream}
|
||||||
onStop={() => {
|
onStop={() => {
|
||||||
@@ -48,7 +43,7 @@ const App = () => {
|
|||||||
topics={webSockets.topics}
|
topics={webSockets.topics}
|
||||||
disconnected={disconnected}
|
disconnected={disconnected}
|
||||||
/>
|
/>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
|
|||||||
import { DefaultApi, V1TranscriptsCreateRequest } from "../api/apis/DefaultApi";
|
import { DefaultApi, V1TranscriptsCreateRequest } from "../api/apis/DefaultApi";
|
||||||
import { Configuration } from "../api/runtime";
|
import { Configuration } from "../api/runtime";
|
||||||
import { GetTranscript } from "../api";
|
import { GetTranscript } from "../api";
|
||||||
|
import getApi from "../lib/getApi";
|
||||||
|
|
||||||
type UseTranscript = {
|
type UseTranscript = {
|
||||||
response: GetTranscript | null;
|
response: GetTranscript | null;
|
||||||
@@ -15,11 +16,7 @@ const useTranscript = (): UseTranscript => {
|
|||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
const apiConfiguration = new Configuration({
|
const api = getApi();
|
||||||
basePath: process.env.NEXT_PUBLIC_API_URL,
|
|
||||||
// accessToken:
|
|
||||||
});
|
|
||||||
const api = new DefaultApi(apiConfiguration);
|
|
||||||
|
|
||||||
const createTranscript = () => {
|
const createTranscript = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
V1TranscriptRecordWebrtcRequest,
|
V1TranscriptRecordWebrtcRequest,
|
||||||
} from "../api/apis/DefaultApi";
|
} from "../api/apis/DefaultApi";
|
||||||
import { Configuration } from "../api/runtime";
|
import { Configuration } from "../api/runtime";
|
||||||
|
import getApi from "../lib/getApi";
|
||||||
|
|
||||||
const useWebRTC = (
|
const useWebRTC = (
|
||||||
stream: MediaStream | null,
|
stream: MediaStream | null,
|
||||||
@@ -17,10 +18,7 @@ const useWebRTC = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiConfiguration = new Configuration({
|
const api = getApi();
|
||||||
basePath: process.env.NEXT_PUBLIC_API_URL,
|
|
||||||
});
|
|
||||||
const api = new DefaultApi(apiConfiguration);
|
|
||||||
|
|
||||||
let p: Peer = new Peer({ initiator: true, stream: stream });
|
let p: Peer = new Peer({ initiator: true, stream: stream });
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import { useFiefUserinfo } from "@fief/fief/nextjs/react";
|
|
||||||
|
|
||||||
export default function UserInfo() {
|
|
||||||
const userinfo = useFiefUserinfo();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{userinfo && (
|
|
||||||
<>
|
|
||||||
<h1>Logged In</h1>
|
|
||||||
<p>{userinfo.email}</p>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!userinfo && (
|
|
||||||
<>
|
|
||||||
<h1>Not Logged In</h1>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user