Auth front-end

This commit is contained in:
Koper
2023-08-18 19:29:02 +07:00
parent 327911c43e
commit 733054428e
15 changed files with 234 additions and 43 deletions

View 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>
);
}

View File

@@ -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

View File

@@ -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();
}
} }

View 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,
};
}

View File

@@ -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";

View File

@@ -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>
<div id="container">
<div className="flex flex-col items-center h-[100svh] bg-gradient-to-r from-[#8ec5fc30] to-[#e0c3fc42]">
<UserInfo /> <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} {children}
</div>
</div>
</FiefWrapper> </FiefWrapper>
</body> </body>
</html> </html>

18
www/app/lib/getApi.ts Normal file
View 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
View 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
}
}

View File

@@ -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> </>
); );
}; };

View File

@@ -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);

View File

@@ -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 });

View File

@@ -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>
</>
)}
</>
);
}