diff --git a/samples/react-associated-hub-links/src/webparts/reactAssociatedHubLinks/ReactAssociatedHubLinksWebPart.ts b/samples/react-associated-hub-links/src/webparts/reactAssociatedHubLinks/ReactAssociatedHubLinksWebPart.ts index 2cd6dd4df..78bcd6690 100644 --- a/samples/react-associated-hub-links/src/webparts/reactAssociatedHubLinks/ReactAssociatedHubLinksWebPart.ts +++ b/samples/react-associated-hub-links/src/webparts/reactAssociatedHubLinks/ReactAssociatedHubLinksWebPart.ts @@ -1,21 +1,20 @@ -import '../../../assets/dist/tailwind.css'; -import '@pnp/sp/search'; -import '@pnp/sp/webs'; -import '@pnp/sp/sites'; +import "../../../assets/dist/tailwind.css"; +import "@pnp/sp/search"; +import "@pnp/sp/webs"; +import "@pnp/sp/sites"; -import * as React from 'react'; -import * as ReactDom from 'react-dom'; +import * as React from "react"; +import * as ReactDom from "react-dom"; -import { Version } from '@microsoft/sp-core-library'; -import { IPropertyPaneConfiguration } from '@microsoft/sp-property-pane'; -import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; -import { SPFI, spfi, SPFx } from '@pnp/sp'; +import { Version } from "@microsoft/sp-core-library"; +import { IPropertyPaneConfiguration } from "@microsoft/sp-property-pane"; +import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base"; +import { SPFI, spfi, SPFx } from "@pnp/sp"; import { - IReactAssociatedHubLinksProps, ReactAssociatedHubLinks -} from './components/ReactAssociatedHubLinks'; -import { ILink } from './utils/ILink'; -import { SearchResults } from '@pnp/sp/search'; + IReactAssociatedHubLinksProps, + ReactAssociatedHubLinks, +} from "./components/ReactAssociatedHubLinks"; export interface IReactAssociatedHubLinksWebPartProps { description: string; @@ -25,29 +24,14 @@ export default class ReactAssociatedHubLinksWebPart extends BaseClientSideWebPar private _sp: SPFI; public async render(): Promise { - const links = await this.getAssociatedSitesLinks(); const element: React.ReactElement = React.createElement(ReactAssociatedHubLinks, { - links, + sp: this._sp, }); ReactDom.render(element, this.domElement); } - protected async getAssociatedSitesLinks() { - const site = await this._sp.site(); - const searchResults: SearchResults = await this._sp.search( - `DepartmentId=${site.Id} contentclass:sts_site -SiteId:${site.Id}` - ); - const associatedSitesLinks: ILink[] = - searchResults.PrimarySearchResults.map((result) => ({ - title: result.Title, - url: result.Path, - logoUrl: result.SiteLogo - } as ILink)); - return associatedSitesLinks; - } - protected async onInit(): Promise { await super.onInit(); this._sp = spfi().using(SPFx(this.context)); diff --git a/samples/react-associated-hub-links/src/webparts/reactAssociatedHubLinks/components/ReactAssociatedHubLinks.tsx b/samples/react-associated-hub-links/src/webparts/reactAssociatedHubLinks/components/ReactAssociatedHubLinks.tsx index 1a1a822bd..1fd9a5440 100644 --- a/samples/react-associated-hub-links/src/webparts/reactAssociatedHubLinks/components/ReactAssociatedHubLinks.tsx +++ b/samples/react-associated-hub-links/src/webparts/reactAssociatedHubLinks/components/ReactAssociatedHubLinks.tsx @@ -1,33 +1,86 @@ -import { Icon } from 'office-ui-fabric-react'; -import * as React from 'react'; +import { SPFI } from "@pnp/sp"; +import { SearchResults } from "@pnp/sp/search"; +import { + Icon, + Shimmer, + ShimmerElementType, +} from "office-ui-fabric-react"; +import * as React from "react"; +import { useEffect, useState } from "react"; -import { ILink } from '../utils/ILink'; +import { ILink } from "../utils/ILink"; interface IReactAssociatedHubLinksProps { - links: ILink[]; + sp: SPFI; } -const ReactAssociatedHubLinks = (props: IReactAssociatedHubLinksProps): JSX.Element => { +const ReactAssociatedHubLinks = ( + props: IReactAssociatedHubLinksProps +): JSX.Element => { + const shimmerElements = [ + { type: ShimmerElementType.line, width: 255.67, height: 66 }, + { type: ShimmerElementType.gap, width: 12 }, + { type: ShimmerElementType.line, width: 255.67, height: 66 }, + { type: ShimmerElementType.gap, width: 12 }, + { type: ShimmerElementType.line, width: 255.67, height: 66 }, + ]; + + const [isDataLeaded, setIsDataLoded] = useState(false); + const [links, setLinks] = useState([]); + + useEffect(() => { + getAssociatedSitesLinks() + .then((result) => { + setLinks(result); + setIsDataLoded(true); + }) + .catch((error) => { + console.error(error); + alert("Failed on getting associated sites links."); + }); + }, []); + + async function getAssociatedSitesLinks(): Promise { + const site = await props.sp.site(); + const searchResults: SearchResults = await props.sp.search( + `DepartmentId=${site.Id} contentclass:sts_site -SiteId:${site.Id}` + ); + return searchResults.PrimarySearchResults.map( + (result): ILink => ({ + title: result.Title, + url: result.Path, + logoUrl: result.SiteLogo, + }) + ); + } + return ( -
- {props.links.map((link) => ( - - {link.logoUrl ? ( - logo - ) : ( - - )} - {link.title} - - ))} -
+ <> + {isDataLeaded ? ( +
+ {links.map((link) => ( + + {link.logoUrl ? ( + logo + ) : ( + + )} + {link.title} + + ))} +
+ ) : ( + + )} + ); };