diff --git a/hosting/src/app/(protected)/content/article/page.tsx b/hosting/src/app/(protected)/content/article/page.tsx index dea7e72f..d34e07d9 100644 --- a/hosting/src/app/(protected)/content/article/page.tsx +++ b/hosting/src/app/(protected)/content/article/page.tsx @@ -13,7 +13,7 @@ import {Suspense, useEffect, useState} from "react"; export default function DocumentTypeDocumentsPage() { const {data: documentType} = useTanamDocumentType("article"); const {create, error: crudError} = useCrudTanamDocument(); - const {data: documents, error: docsError} = useTanamDocuments("article"); + const {data: documents, error: docsError, isLoading} = useTanamDocuments("article"); const [notification, setNotification] = useState(null); const router = useRouter(); @@ -53,7 +53,11 @@ export default function DocumentTypeDocumentsPage() { )} }> - {documentType ? : } + {documentType ? ( + + ) : ( + + )} ); diff --git a/hosting/src/components/DocumentType/DocumentTypeGenericList.tsx b/hosting/src/components/DocumentType/DocumentTypeGenericList.tsx index 770f417f..eafa1210 100644 --- a/hosting/src/components/DocumentType/DocumentTypeGenericList.tsx +++ b/hosting/src/components/DocumentType/DocumentTypeGenericList.tsx @@ -6,28 +6,28 @@ import Link from "next/link"; interface TableOverviewGenericProps { documentType: TanamDocumentTypeClient; documents: TanamDocumentClient[]; + isLoading?: boolean; } -export function DocumentTypeGenericList({documents, documentType}: TableOverviewGenericProps) { +export function DocumentTypeGenericList({documents, documentType, isLoading}: TableOverviewGenericProps) { return ( - <> - [ - -

{document.data[documentType.titleField] as string}

- , -

- {document.createdAt?.toDate().toUTCString()} -

, +
[ + +

{document.data[documentType.titleField] as string}

+ , +

+ {document.createdAt?.toDate().toUTCString()} +

, - , - ])} - /> - + , + ])} + /> ); } diff --git a/hosting/src/components/Table/Table.tsx b/hosting/src/components/Table/Table.tsx index 6ce20267..34d47f0d 100644 --- a/hosting/src/components/Table/Table.tsx +++ b/hosting/src/components/Table/Table.tsx @@ -1,8 +1,9 @@ -import React from "react"; +import React, {FC} from "react"; interface TableProps { headers: string[]; rows: React.ReactNode[][]; + isLoading?: boolean; } /** @@ -22,13 +23,14 @@ interface TableProps { * onDownload={() => console.log("Download", document)} * />, * ])} + * isLoading={true} * /> * ``` * * @param {TableProps} param0 Table parameters * @return {JSX.Element} Table component */ -export function Table({headers, rows}: TableProps): JSX.Element { +export function Table({headers, rows, isLoading = false}: TableProps): JSX.Element { return (
@@ -43,18 +45,38 @@ export function Table({headers, rows}: TableProps): JSX.Element {
- {rows.map((row, rowIndex) => ( - - {row.map((col, colIndex) => ( - - ))} - - ))} + {isLoading + ? Array.from({length: 20}).map((_, rowIndex) => ) + : rows.map((row, rowIndex) => )}
- {col} -
); } + +const TableRowShimmer: FC<{ + headers: string[]; + rowIndex?: number; +}> = ({headers, rowIndex}) => ( + + {headers.map((_, colIndex) => ( + +
+ + ))} + +); + +const TableRow: FC<{ + row: React.ReactNode[]; + rowIndex?: number; +}> = ({row, rowIndex}) => ( + + {row.map((col, colIndex) => ( + + {col} + + ))} + +); diff --git a/hosting/src/hooks/useTanamDocuments.tsx b/hosting/src/hooks/useTanamDocuments.tsx index 816c7e44..83184a59 100644 --- a/hosting/src/hooks/useTanamDocuments.tsx +++ b/hosting/src/hooks/useTanamDocuments.tsx @@ -9,6 +9,7 @@ import {useEffect, useState} from "react"; interface UseTanamDocumentsResult { data: TanamDocumentClient[]; error: UserNotification | null; + isLoading: boolean; } /** @@ -20,10 +21,12 @@ interface UseTanamDocumentsResult { export function useTanamDocuments(documentTypeId?: string): UseTanamDocumentsResult { const [data, setData] = useState([]); const [error, setError] = useState(null); + const [isLoading, setIsLoading] = useState(true); useEffect(() => { if (!documentTypeId) { setError(new UserNotification("error", "Missing parameter", "Content type parameter is missing")); + setIsLoading(false); return; } @@ -35,9 +38,11 @@ export function useTanamDocuments(documentTypeId?: string): UseTanamDocumentsRes (snapshot) => { const documents = snapshot.docs.map((doc) => TanamDocumentClient.fromFirestore(doc)); setData(documents); + setIsLoading(false); }, (err) => { setError(new UserNotification("error", "Error fetching data", err.message)); + setIsLoading(false); }, ); @@ -45,28 +50,31 @@ export function useTanamDocuments(documentTypeId?: string): UseTanamDocumentsRes return () => unsubscribe(); }, [documentTypeId]); - return {data, error}; + return {data, error, isLoading}; } interface UseTanamDocumentResult { data: TanamDocumentClient | null; changeStatus: (status: TanamPublishStatus) => Promise; error: UserNotification | null; + isLoading: boolean; } /** * Hook to get a subscription for a single document * * @param {string?} documentId Document id - * @return {UseTanamDocumentsResult} Hook for document subscription + * @return {UseTanamDocumentResult} Hook for document subscription */ export function useTanamDocument(documentId?: string): UseTanamDocumentResult { const [data, setData] = useState(null); const [error, setError] = useState(null); + const [isLoading, setIsLoading] = useState(true); useEffect(() => { if (!documentId) { setError(new UserNotification("error", "Missing parameter", "Document id parameter is missing")); + setIsLoading(false); return; } const docRef = doc(firestore, "tanam-documents", documentId); @@ -74,9 +82,11 @@ export function useTanamDocument(documentId?: string): UseTanamDocumentResult { docRef, (snapshot) => { setData(TanamDocumentClient.fromFirestore(snapshot)); + setIsLoading(false); }, (err) => { setError(new UserNotification("error", "Error fetching data", err.message)); + setIsLoading(false); }, ); @@ -109,7 +119,7 @@ export function useTanamDocument(documentId?: string): UseTanamDocumentResult { } } - return {data, changeStatus, error}; + return {data, changeStatus, error, isLoading}; } export function useCrudTanamDocument() {