diff --git a/functions/src/models/TanamUser.ts b/functions/src/models/TanamUser.ts index 8f5f545d..ae372bf6 100644 --- a/functions/src/models/TanamUser.ts +++ b/functions/src/models/TanamUser.ts @@ -2,6 +2,7 @@ export type TanamRole = "publisher" | "admin"; export interface ITanamUser { role?: TanamRole; + name?: string; createdAt: TimestampType; updatedAt: TimestampType; } @@ -9,6 +10,7 @@ export interface ITanamUser { export abstract class TanamUser { constructor(id: string, json: ITanamUser) { this.id = id; + this.name = json.name; this.role = json.role ?? "publisher"; this.createdAt = json.createdAt; this.updatedAt = json.updatedAt; @@ -16,6 +18,7 @@ export abstract class TanamUser { public readonly id: string; public role: TanamRole; + public name?: string; public readonly createdAt: TimestampType; public readonly updatedAt: TimestampType; @@ -24,6 +27,7 @@ export abstract class TanamUser { toJson(): object { return { role: this.role, + name: this.name, createdAt: this.createdAt ?? this.getServerTimestamp(), updatedAt: this.getServerTimestamp(), }; diff --git a/functions/src/models/TanamUserAdmin.ts b/functions/src/models/TanamUserAdmin.ts index 40d3af19..1793b4e0 100644 --- a/functions/src/models/TanamUserAdmin.ts +++ b/functions/src/models/TanamUserAdmin.ts @@ -19,6 +19,7 @@ export class TanamUserAdmin extends TanamUser { return new TanamUserAdmin(snap.id, { role: data.role, + name: data.name, createdAt: data.createdAt || Timestamp.now(), updatedAt: data.updatedAt || Timestamp.now(), }); diff --git a/functions/src/models/shared.ts b/functions/src/models/shared.ts index fc48fe84..306e6f30 100644 --- a/functions/src/models/shared.ts +++ b/functions/src/models/shared.ts @@ -4,6 +4,7 @@ // if there are load dependency packages in them and some packages sometimes only support server side. export * from "./LocalizedString"; export * from "./TanamDocument"; +export * from "./TanamDocumentData"; export * from "./TanamDocumentField"; export * from "./TanamDocumentType"; -export * from "./TanamDocumentData"; +export * from "./TanamUser"; diff --git a/functions/src/triggers/users.ts b/functions/src/triggers/users.ts index afe2166b..a876e29e 100644 --- a/functions/src/triggers/users.ts +++ b/functions/src/triggers/users.ts @@ -24,9 +24,11 @@ export const onTanamUserCreated = onDocumentCreated("tanam-users/{docId}", async return docRef.delete(); } + const firebaseUser = await auth.getUser(uid); const existingDocs = await db.collection("tanam-users").get(); const tanamUser = new TanamUserAdmin(uid, { ...docData, + name: firebaseUser.displayName, role: existingDocs.size === 1 ? "admin" : "publisher", createdAt: Timestamp.now(), updatedAt: Timestamp.now(), diff --git a/hosting/src/components/Header/index.tsx b/hosting/src/components/Header/index.tsx index 37b5e5d6..750a625d 100644 --- a/hosting/src/components/Header/index.tsx +++ b/hosting/src/components/Header/index.tsx @@ -3,9 +3,17 @@ import DropdownUser from "@/components/Header/DropdownUser"; import {useAuthentication} from "@/hooks/useAuthentication"; import Image from "next/image"; import Link from "next/link"; +import {useEffect} from "react"; +import {useTanamUser} from "../../hooks/useTanamUser"; const Header = (props: {sidebarOpen: string | boolean | undefined; setSidebarOpen: (arg0: boolean) => void}) => { const {authUser} = useAuthentication(); + const {data: tanamUser, error: userError} = useTanamUser(authUser?.uid); + + useEffect(() => { + console.log("userError", userError); + }, [userError]); + return (
@@ -76,8 +84,7 @@ const Header = (props: {sidebarOpen: string | boolean | undefined; setSidebarOpe
- - + {tanamUser ? : <>}
diff --git a/hosting/src/hooks/useTanamUser.tsx b/hosting/src/hooks/useTanamUser.tsx new file mode 100644 index 00000000..4ac40bd1 --- /dev/null +++ b/hosting/src/hooks/useTanamUser.tsx @@ -0,0 +1,45 @@ +import {TanamUserClient} from "@/models/TanamUserClient"; +import {UserNotification} from "@/models/UserNotification"; +import {firestore} from "@/plugins/firebase"; +import {doc, onSnapshot} from "firebase/firestore"; +import {useEffect, useState} from "react"; + +interface UseTanamDocumentsResult { + data: TanamUserClient | null; + error: UserNotification | null; +} + +/** + * Hook to get a Tanam user document from Firestore + * + * @param {string?} uid User ID + * @return {UseTanamDocumentsResult} Hook for documents subscription + */ +export function useTanamUser(uid?: string): UseTanamDocumentsResult { + const [data, setData] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + if (!uid) { + setData(null); + return; + } + + const docRef = doc(firestore, `tanam-users`, uid); + const unsubscribe = onSnapshot( + docRef, + (snapshot) => { + const tanamUser = TanamUserClient.fromFirestore(snapshot); + setData(tanamUser); + }, + (err) => { + setError(new UserNotification("error", "Error fetching user", err.message)); + }, + ); + + // Cleanup subscription on unmount + return () => unsubscribe(); + }, [uid]); + + return {data, error}; +} diff --git a/hosting/src/models/TanamUserClient.ts b/hosting/src/models/TanamUserClient.ts new file mode 100644 index 00000000..2f17b916 --- /dev/null +++ b/hosting/src/models/TanamUserClient.ts @@ -0,0 +1,26 @@ +import {ITanamUser, TanamUser} from "@functions/models/TanamUser"; +import {DocumentSnapshot, FieldValue, serverTimestamp, Timestamp} from "firebase/firestore"; + +export class TanamUserClient extends TanamUser { + constructor(id: string, json: ITanamUser) { + super(id, json); + } + + getServerTimestamp(): FieldValue { + return serverTimestamp(); + } + + static fromFirestore(snap: DocumentSnapshot): TanamUserClient { + const data = snap.data(); + if (!data) { + throw new Error("Document data is undefined"); + } + + return new TanamUserClient(snap.id, { + role: data.role, + name: data.name, + createdAt: data.createdAt || Timestamp.now(), + updatedAt: data.updatedAt || Timestamp.now(), + }); + } +}