+ {!this.state.cB &&
+ !this.state.ChampionsList &&
+ !this.state.addMember && !this.state.manageApprovals &&
+ !this.state.dB && !this.state.enableTOT && !this.state.championReport && (
+
+
+ {LocaleStrings.WelcomeLabel} {this.state.firstName}!
+
+
+
+ {LocaleStrings.GetStartedLabel}
+
- this.setState({
- addMember: !this.state.addMember,
- })
- }
+ className={`${styles.cursor}${isDarkOrContrastTheme ? " " + styles.cursorDarkContrast : ""}`}
+ onClick={() => this.setState({ cB: !this.state.cB })}
+ onKeyDown={(evt: any) => { if (evt.key === stringsConstants.stringEnter) this.setState({ cB: !this.state.cB }) }}
>
-
- {(this.state.clB && !this.state.cV) ? LocaleStrings.AddMemberLabel : LocaleStrings.NominateMemberLabel}
+
+ {LocaleStrings.ChampionLeaderBoardLabel}
- )}
- {(this.state.cV || this.state.clB) && (
-
-
this.setState({ dB: !this.state.dB })}
- >
-
-
-
{LocaleStrings.DigitalBadgeLabel}
-
-
-
- )}
- {this.state.isTOTEnabled && (
-
-
+ {(this.state.cV || this.state.clB) && (
+
this.setState({ enableTOT: !this.state.enableTOT })}
+ className={`${styles.cursor}${isDarkOrContrastTheme ? " " + styles.cursorDarkContrast : ""}`}
+ onKeyDown={(evt: any) => {
+ if (evt.key === stringsConstants.stringEnter) this.setState({
+ addMember: !this.state.addMember,
+ })
+ }}
+ onClick={() =>
+ this.setState({
+ addMember: !this.state.addMember,
+ })
+ }
>
-
+
- {this.state.isTOTEnabled && (
- {LocaleStrings.TOTLabel}
)}
+
+ {(this.state.clB && !this.state.cV) ? LocaleStrings.AddMemberLabel : LocaleStrings.NominateMemberLabel}
+
-
- )}
-
-
- {this.state.clB && !this.state.cV && (
- {LocaleStrings.AdminToolsLabel}
)}
-
- {this.state.clB && !this.state.cV && (
-
-
-
- this.setState({
- manageApprovals: !this.state.manageApprovals,
- })
- }
- >
-
-
-
- {LocaleStrings.AdminTasksLabel}
-
-
-
-
-
-
-
+
+
+ )}
+ {this.state.isTOTEnabled && (
+
+
+
this.setState({ enableTOT: !this.state.enableTOT })}
+ onKeyDown={(evt: any) => { if (evt.key === stringsConstants.stringEnter) this.setState({ enableTOT: !this.state.enableTOT }) }}
>
-
-
- {LocaleStrings.EventsListLabel}
+
+
+ {this.state.isTOTEnabled && (
+ {LocaleStrings.TOTLabel}
)}
+
+
-
-
-
-
-
- )
- }
- {
- this.state.cB && this.state.clB && (
- this.setState({ clB: true, cB: false })}
- />
- )
- }
- {
- this.state.cB && this.state.cV && (
- this.setState({ clB: false, cB: false })}
- />
- )
- }
- {
- this.state.enableTOT && (
-
- )
- }
- {
- this.state.addMember && (
- { this.setState({ addMember: false }); }}
- onHomeCallBack={this.callBackFunction}
- />
- )
- }
- {
- this.state.manageApprovals && (
-
- )
- }
- {
- this.state.cB && this.state.eV && (
- this.setState({ eV: true, cB: false })}
- />
- )
- }
- {
- this.state.dB && (
- this.setState({ dB: false })}
- clickcallchampionview={() =>
- this.setState({ cB: false, eV: false, dB: false })
- }
- />
- )
- }
-
-
+ )
+ }
+ {
+ this.state.cB && this.state.clB && (
+ this.setState({ clB: true, cB: false })}
+ loggedinUserEmail={this.state.loggedinUserEmail}
+ currentThemeName={this.state.currentThemeName}
+ />
+ )
+ }
+ {
+ this.state.cB && this.state.cV && (
+ this.setState({ clB: false, cB: false })}
+ loggedinUserEmail={this.state.loggedinUserEmail}
+ currentThemeName={this.state.currentThemeName}
+ />
+ )
+ }
+ {
+ this.state.enableTOT && (
+
+ )
+ }
+ {
+ this.state.addMember && (
+ { this.setState({ addMember: false }); }}
+ onHomeCallBack={this.callBackFunction}
+ currentThemeName={this.state.currentThemeName}
+ />
+ )
+ }
+ {
+ this.state.manageApprovals && (
+
+ )
+ }
+ {
+ this.state.cB && this.state.eV && (
+ this.setState({ eV: true, cB: false })}
+ currentThemeName={this.state.currentThemeName}
+ />
+ )
+ }
+ {
+ this.state.dB && (
+ this.setState({ dB: false })}
+ currentThemeName={this.state.currentThemeName}
+ />
+ )
+ }
+ {
+ this.state.championReport && (
+
+ {
+ this.setState({ championReport: false });
+ }}
+ />
+ )}
+
+
+
);
}
}
diff --git a/src/webparts/clbHome/components/DigitalBadge.tsx b/src/webparts/clbHome/components/DigitalBadge.tsx
index c80d41ff..be6bb9d9 100644
--- a/src/webparts/clbHome/components/DigitalBadge.tsx
+++ b/src/webparts/clbHome/components/DigitalBadge.tsx
@@ -1,57 +1,25 @@
-import { Icon } from '@fluentui/react/lib/Icon';
-import { List } from '@fluentui/react/lib/List';
-import { IRectangle } from '@fluentui/react/lib/Utilities';
+import * as React from "react";
+import {
+ Icon, List, IRectangle, PrimaryButton, MessageBar,
+ MessageBarType, Spinner, SpinnerSize, DefaultButton
+} from '@fluentui/react';
import { MSGraphClientV3, SPHttpClient, SPHttpClientResponse } from "@microsoft/sp-http";
import { WebPartContext } from "@microsoft/sp-webpart-base";
-import * as microsoftTeams from "@microsoft/teams-js";
-import { initializeIcons } from "@uifabric/icons";
-import * as LocaleStrings from 'ClbHomeWebPartStrings';
-import * as $ from "jquery";
-import {
- ConnectedComponent,
- Panel,
- PanelBody, PanelFooter, PanelHeader, Surface, TeamsComponentContext, ThemeStyle
-} from "msteams-ui-components-react";
-import {
- anchor, getContext,
- primaryButton
-} from "msteams-ui-styles-core";
-import {
- PrimaryButton
-} from "office-ui-fabric-react/lib/Button";
-import {
- MessageBar,
- MessageBarType
-} from "office-ui-fabric-react/lib/MessageBar";
-import { Spinner, SpinnerSize } from "office-ui-fabric-react/lib/Spinner";
-import * as React from "react";
-import "../assets/stylesheets/DigitalBadgeProfile.scss";
import commonServices from '../Common/CommonServices';
import siteconfig from "../config/siteconfig.json";
import * as strings from "../constants/strings";
-import IProfileImage from "../models/IProfileImage";
+import * as LocaleStrings from 'ClbHomeWebPartStrings';
import dbStyles from "../scss/CMPDigitalBadge.module.scss";
-import {
- ITeamsBaseComponentProps,
- ITeamsBaseComponentState, TeamsBaseComponent
-} from "./TeamsBaseComponent";
-
-const config = {
- baseFontSize: 16,
- style: ThemeStyle.Light,
-};
-const contextCSS = getContext(config);
const graphUrl = "https://graph.microsoft.com";
const graphMyPhotoApiUrl = graphUrl + "/v1.0/me/photo";
const graphMyPhotoBitsUrl = graphMyPhotoApiUrl + "/$value";
let upn: string | undefined = "";
-export interface IDigitalBadgeState extends ITeamsBaseComponentState {
- entityId?: string;
+export interface IDigitalBadgeState {
isLoading: boolean;
themeLoaded: boolean;
- profileImage?: IProfileImage;
+ profileImage: IProfileImage;
isLoggedIn: boolean;
hasAccepted: boolean;
hasImageSelected: boolean;
@@ -59,7 +27,6 @@ export interface IDigitalBadgeState extends ITeamsBaseComponentState {
isApplying: boolean;
isApplied: boolean;
error: string;
- upn?: string;
imageDownloaded: boolean;
downloadText: string;
showAccept: boolean;
@@ -69,50 +36,33 @@ export interface IDigitalBadgeState extends ITeamsBaseComponentState {
inclusionpath: string;
allBadgeImages: string[];
noBadgesFlag: boolean;
+ digitalBadgeScreen: string;
}
-export interface IDigitalBadgeProps extends ITeamsBaseComponentProps {
- clientId: string;
- description: string;
+export interface IDigitalBadgeProps {
context: WebPartContext;
clickcallback: () => void;
- clickcallchampionview: () => void;
siteUrl: string;
+ appTitle: string;
+ currentThemeName?: string;
}
-export default class DigitalBadge extends TeamsBaseComponent<
- IDigitalBadgeProps,
- IDigitalBadgeState
-> {
+export interface IProfileImage {
+ url: string;
+ width: number;
+}
+
+export default class DigitalBadge extends React.Component
{
private columnCount = 0;
private rowHeight = 0;
private ROWS_PER_PAGE = 3;
private MAX_ROW_HEIGHT = 300;
private commonServiceManager: commonServices;
- constructor(props: IDigitalBadgeProps, states: IDigitalBadgeState) {
- super(props, states);
- this.commonServiceManager = new commonServices(this.props.context, this.props.siteUrl);
- this._onDownloadImage = this._onDownloadImage.bind(this);
- this.onUserAcceptance = this.onUserAcceptance.bind(this);
- this.onBadgeSelected = this.onBadgeSelected.bind(this);
- this._onApplyProfileImage = this._onApplyProfileImage.bind(this);
- this.getPhotoBits = this.getPhotoBits.bind(this);
- this.getAllBadgeImages = this.getAllBadgeImages.bind(this);
- this.onRenderCell = this.onRenderCell.bind(this);
- this.getItemCountForPageService = this.getItemCountForPageService.bind(this);
- }
-
- private _requestOptions: {} = {
- headers: {
- "X-ClientTag": "NONISV|Microsoft|ChampBadge/1.0.0",
- },
- };
- public componentWillMount() {
- initializeIcons();
+ constructor(props: IDigitalBadgeProps) {
+ super(props);
let profile: IProfileImage = { url: "", width: 0 };
-
- this.setState({
- fontSize: this.pageFontSize(),
+ //State object Initialization
+ this.state = {
isLoading: true,
themeLoaded: false,
profileImage: profile,
@@ -131,14 +81,65 @@ export default class DigitalBadge extends TeamsBaseComponent<
inclusionpath: siteconfig.inclusionPath,
siteUrl: this.props.siteUrl,
allBadgeImages: [],
- noBadgesFlag: false
- });
+ noBadgesFlag: false,
+ digitalBadgeScreen: strings.digitalBadgeScreen1
+ };
+ this.commonServiceManager = new commonServices(this.props.context, this.props.siteUrl);
+ this._onDownloadImage = this._onDownloadImage.bind(this);
+ this.onUserAcceptance = this.onUserAcceptance.bind(this);
+ this.onBadgeSelected = this.onBadgeSelected.bind(this);
+ this._onApplyProfileImage = this._onApplyProfileImage.bind(this);
+ this.getPhotoBits = this.getPhotoBits.bind(this);
+ this.getAllBadgeImages = this.getAllBadgeImages.bind(this);
+ this.onRenderCell = this.onRenderCell.bind(this);
+ this.getItemCountForPageService = this.getItemCountForPageService.bind(this);
+ this.navigateBack = this.navigateBack.bind(this);
+ }
- this.forceUpdate();
- setTimeout(() => {
- this._renderListAsync();
- }, 100);
+ //Component Life cycle method, gets called while the component is getting mounted
+ public componentDidMount(): void {
+ this._renderListAsync();
+ }
+ //component life cycle method, gets called whenever the component is updated
+ //update aria-label attribute to 'open outlook web application' link in digital badge apply screen
+ public componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void {
+ if (prevState.hasImageSelected !== this.state.hasImageSelected) {
+ document.getElementById("linkToChangeProfileImage")?.setAttribute("aria-label", LocaleStrings.digitalBadgeProfileAriaLabel);
+ }
+ }
+
+ //Get currents user's details from Sharepoint Profiles for Digital Badge processing
+ private _renderListAsync() {
+ this.props.context.spHttpClient
+ .get(
+ "/" + this.state.inclusionpath + "/" + this.state.sitename +
+ "/_api/SP.UserProfiles.PeopleManager/GetMyProperties",
+ SPHttpClient.configurations.v1
+ )
+ .then((responseuser: SPHttpClientResponse) => {
+ responseuser.json().then((datauser: any) => {
+ let userassignletters = "";
+ let usernamearray = datauser.DisplayName.split(" ");
+ if (usernamearray.length === 1) {
+ userassignletters = usernamearray[0][0].toUpperCase();
+ }
+ else if (usernamearray.length > 1) {
+ userassignletters =
+ usernamearray[0][0].toUpperCase() +
+ usernamearray[
+ usernamearray.length - 1
+ ][0].toUpperCase();
+ }
+ upn = datauser.Email;
+ this.setState({
+ showAccept: true,
+ userletters: userassignletters,
+ isLoading: false,
+ });
+ this.showUserInformation();
+ });
+ });
}
//Method to get how many items to render per page from specified index
@@ -149,7 +150,7 @@ export default class DigitalBadge extends TeamsBaseComponent<
return serviceObj.itemCountForPage;
}
- //Multiple Badges
+ //Multiple Badges section starts
//Render Fluent UI list cell to show the images and hyperlinks
private onRenderCell = (item: any, index: number | undefined) => {
try {
@@ -163,7 +164,7 @@ export default class DigitalBadge extends TeamsBaseComponent<
>
-
{ this.onBadgeSelected(item.url); })}>
+ { this.onBadgeSelected(item.url); })} role="button">
{this.state.profileImage.url && (
<>
{this.state.profileImage.url !==
@@ -188,8 +189,13 @@ export default class DigitalBadge extends TeamsBaseComponent<
src={item.url}
title={item.enabled ? "" : LocaleStrings.BadgePointsTooltip + " " + item.points}
/>
- {this.state.userletters}
- {item.title}
+ {this.state.userletters}
+ { if (evt.key === strings.stringEnter) this.onBadgeSelected(item.url) })}
+ aria-label={item.title}
+ >
+ {item.title}
+
>
)}
@@ -212,9 +218,10 @@ export default class DigitalBadge extends TeamsBaseComponent<
try {
this.setState({
hasImageSelected: true,
+ digitalBadgeScreen: strings.digitalBadgeScreen3,
imageURL: img,
});
- this.showUserInformation(upn);
+ this.showUserInformation();
}
catch (error) {
console.error("CMP_DigitalBadge_onBadgeSelected \n", JSON.stringify(error));
@@ -282,495 +289,382 @@ export default class DigitalBadge extends TeamsBaseComponent<
}
//Multiple Badges Section Ends
- //Get currents user's details from Mmber List for Digital Badge processing
- private _renderListAsync() {
- microsoftTeams.initialize();
- microsoftTeams.registerOnThemeChangeHandler(this.updateTheme);
- microsoftTeams.getContext((context: microsoftTeams.Context) => {
- this.props.context.spHttpClient
- .get(
- "/" + this.state.inclusionpath + "/" + this.state.sitename +
- "/_api/SP.UserProfiles.PeopleManager/GetMyProperties",
- SPHttpClient.configurations.v1
- )
- .then((responseuser: SPHttpClientResponse) => {
- responseuser.json().then((datauser: any) => {
-
- let userassignletters = "";
- let usernamearray = datauser.DisplayName.split(" ");
- if (usernamearray.length === 1) {
- userassignletters = usernamearray[0][0].toUpperCase();
- } else if (usernamearray.length > 1) {
- userassignletters =
- usernamearray[0][0].toUpperCase() +
- usernamearray[
- usernamearray.length - 1
- ][0].toUpperCase();
- }
- this.setState({
- showAccept: true,
- userletters: userassignletters,
- });
-
- this.updateTheme(context.theme);
- upn = datauser.Email;
- this.setState({
- isLoading: false,
- entityId: context.entityId,
- upn: context.upn,
- });
- this.showUserInformation(upn);
- });
+ //Method to navigate back
+ private navigateBack() {
+ try {
+ if (this.state.digitalBadgeScreen === strings.digitalBadgeScreen1) {
+ this.props.clickcallback();
+ }
+ else if (this.state.digitalBadgeScreen === strings.digitalBadgeScreen2) {
+ this.setState({
+ hasAccepted: false,
+ showAccept: true,
+ digitalBadgeScreen: strings.digitalBadgeScreen1,
+ noBadgesFlag: false,
+ allBadgeImages: [],
});
- });
+ }
+ else if (this.state.digitalBadgeScreen === strings.digitalBadgeScreen3) {
+ this.setState({
+ hasImageSelected: false,
+ isApplied: false
+ });
+ this.onUserAcceptance();
+ }
+ }
+ catch (error: any) {
+ console.error("CMP_DigitalBadge_NavigateBack \n", JSON.stringify(error));
+ }
}
-
public render(): React.ReactElement
{
-
+ const isDarkOrContrastTheme = this.props.currentThemeName === strings.themeDarkMode || this.props.currentThemeName === strings.themeContrastMode;
return (
-
+
{this.state.isLoading && (
-
+
+
+
)}
{!this.state.isLoading && (
-
- {
- const { context } = props;
- const { rem, font, colors, style } = context;
- const { sizes, weights } = font;
- contextCSS.style = this.state.theme;
- const styleProps: any = {};
- switch (style) {
- case ThemeStyle.Dark:
- styleProps.color = colors.dark.brand00;
- break;
- case ThemeStyle.HighContrast:
- styleProps.color = colors.highContrast.white;
- break;
- case ThemeStyle.Light:
- default:
- styleProps.color = colors.light.brand00;
- }
- const styles = {
- header: { ...sizes.title, ...weights.semibold },
- section: {
- ...sizes.base,
- marginTop: rem(1.4),
- marginBottom: rem(1.4),
- },
- footer: { ...sizes.xsmall },
- div: {},
- };
- const anchorClass: string = anchor(contextCSS);
-
- return (
-
-
-
-
-
+
+
+
+
{ if (evt.key === strings.stringEnter || evt.key === strings.stringSpace) this.props.clickcallback(); }}
+ aria-label={this.props.appTitle}
+ >
+
+ {this.props.appTitle}
+
+
+
+
{LocaleStrings.DigitalBadgePageTitle}
+
+
+
+
+
+ {this.state.isLoading && (
+
+ )}
+ {!this.state.isLoading && (
+
+
+ {!this.state.hasAccepted && (
+
+
+
+ {LocaleStrings.PreAcceptPageTitle}
+
+
+
+
+ )}
+
+ {!this.state.hasAccepted &&
+ this.state.showAccept && (
+ <>
+
+
+
+ >
+ )}
+
+ {!this.state.hasAccepted &&
+ this.state.showAccept && (
+
+ )}
+ {!this.state.hasAccepted &&
+ !this.state.showAccept && (
+
+
+
{LocaleStrings.HowtoGetDigitalBadgeText}
+
+ )}
+
+
+ {this.state.hasAccepted && !this.state.hasImageSelected && (
+
+
+ {this.state.noBadgesFlag && (
+
+ )}
+
this.commonServiceManager.getPageHeight(this.rowHeight, this.ROWS_PER_PAGE)}
+ onRenderCell={this.onRenderCell}
/>
-
- {LocaleStrings.CMPBreadcrumbLabel}
-
-
- {LocaleStrings.DigitalBadgePageTitle}
-
-
-
-
- {this.state.isLoading && (
-
- )}
- {!this.state.isLoading && (
-
-
- {!this.state.hasAccepted && (
-
-
- {LocaleStrings.PreAcceptPageTitle}
-
-
- {this.state.badgeImgURL}
-
- )}
-
- {!this.state.hasAccepted &&
- this.state.showAccept && (
-
- )}
-
- {!this.state.hasAccepted &&
- this.state.showAccept && (
-
- )}
- {!this.state.hasAccepted &&
- !this.state.showAccept && (
-
-
-
- {LocaleStrings.HowtoGetDigitalBadgeText}
-
-
- )}
-
+ )}
+ {this.state.hasAccepted && this.state.hasImageSelected && (
+
+
{LocaleStrings.DigitalBadgeSubPageTitle}
+
+ )}
+
+
+
+ {this.state.profileImage.url &&
+ this.state.hasAccepted &&
+ this.state.hasImageSelected &&
+ this.state.profileImage.url !==
+ "../assets/images/noimage.png" && (
+
+
+
- {this.state.hasAccepted && !this.state.hasImageSelected && (
-
-
- {this.state.noBadgesFlag && (
-
- )}
-
this.commonServiceManager.getPageHeight(this.rowHeight, this.ROWS_PER_PAGE)}
- onRenderCell={this.onRenderCell.bind(this)}
- />
-
- )}
- {this.state.hasAccepted && this.state.hasImageSelected && (
-
- {LocaleStrings.DigitalBadgeSubPageTitle}
-
- )}
-
-
-
- {this.state.profileImage.url &&
- this.state.hasAccepted &&
- this.state.hasImageSelected &&
- this.state.profileImage.url !==
- "../assets/images/noimage.png" && (
-
-
-
-
- )}
- {this.state.profileImage.url &&
- this.state.profileImage.url ===
- "../assets/images/noimage.png" &&
- this.state.hasAccepted &&
- this.state.hasImageSelected && (
-
-
-
- {this.state.userletters}
-
-
-
- )}
- {!this.state.profileImage.url &&
- this.state.hasAccepted &&
- this.state.hasImageSelected && (
-
-
-
- )}
-
- {!this.state.isApplying &&
- this.state.profileImage.url &&
- this.state.hasAccepted &&
- this.state.hasImageSelected &&
- !this.state.isApplying &&
- !this.state.isApplied && (
-
-
0
- }
- title={LocaleStrings.ApplyButton}
- >
-
- {LocaleStrings.ApplyButtonText}
-
-
- {this.state.profileImage.url !==
- "../assets/images/noimage.png" && (
-
-
- {this.state.downloadText}
-
-
- )}
-
- )}
-
-
- {this.state.hasAccepted &&
- this.state.hasImageSelected &&
- !this.state.isApplied &&
- this.state.profileImage.url &&
- this.state.profileImage.url !==
- "../assets/images/noimage.png" && (
-
- )}
- {this.state.hasAccepted &&
- this.state.hasImageSelected &&
- !this.state.isApplied &&
- this.state.profileImage.url && (
-
- )}
-
+ )}
+ {this.state.profileImage.url &&
+ this.state.profileImage.url ===
+ "../assets/images/noimage.png" &&
+ this.state.hasAccepted &&
+ this.state.hasImageSelected && (
+
+
+
{this.state.userletters}
+
- {!this.state.profileImage.url &&
- this.state.hasAccepted &&
- this.state.hasImageSelected && (
-
- )}
- {!this.state.isApplying && (
-
- {!this.state.hasAccepted &&
- this.state.showAccept && (
-
-
- {LocaleStrings.AcceptButtonText}
-
- )}
- {!this.state.hasAccepted &&
- !this.state.showAccept && (
-
- )}
-
- )}
- {this.state.isApplying &&
- !this.state.isApplied && (
-
-
-
- )}
- {this.state.isApplied &&
- !this.state.isApplying && (
-
-
+
+
+ )}
+
+ {!this.state.isApplying &&
+ this.state.profileImage.url &&
+ this.state.hasAccepted &&
+ this.state.hasImageSelected &&
+ !this.state.isApplied && (
+
+
0
+ }
+ title={LocaleStrings.ApplyButton}
+ >
+
+ {LocaleStrings.ApplyButtonText}
+
+
+ {this.state.profileImage.url !==
+ "../assets/images/noimage.png" && (
+
+
-
-
+ {this.state.downloadText}
+
)}
- {this.state.error && (
-
-
- {this.state.error}
-
-
- )}
-
+
)}
-
-
-
-
- {this.state.entityId}
+
+ {this.state.hasAccepted &&
+ this.state.hasImageSelected &&
+ !this.state.isApplied &&
+ this.state.profileImage.url &&
+ this.state.profileImage.url !==
+ "../assets/images/noimage.png" && (
+
+ )}
+ {this.state.hasAccepted &&
+ this.state.hasImageSelected &&
+ !this.state.isApplied &&
+ this.state.profileImage.url && (
+ <>
+
+
+ >
+ )}
-
-
-
-
-
-
- );
- }}
- >
-
+
+ {!this.state.profileImage.url &&
+ this.state.hasAccepted &&
+ this.state.hasImageSelected && (
+
+ )}
+ {this.state.isApplying &&
+ !this.state.isApplied && (
+
+
+
+ )}
+ {this.state.isApplied &&
+ !this.state.isApplying && (
+
+
+
+
+
+ )}
+ {this.state.error && (
+
+
+ {this.state.error}
+
+
+ )}
+
+
+ {!this.state.isApplying && (
+
+ {!this.state.hasAccepted &&
+ this.state.showAccept && (
+
+
+ {LocaleStrings.AcceptButtonText}
+
+ )}
+ {!this.state.hasAccepted &&
+ !this.state.showAccept && (
+
+ )}
+
+ )}
+
+
+ )}
+
+
+
+
+
+ >
)}
);
}
+
public createMarkup(markup: string, anchorClass: string = "") {
if (markup.indexOf(strings.ANCHOR_ID) !== -1 && anchorClass !== "") {
markup = markup.replace(strings.ANCHOR_ID, anchorClass);
}
return { __html: markup };
}
- public getPhotoBits(): Promise {
+ public async getPhotoBits(): Promise {
let canvas: any = document.getElementById("profileCanvas");
if (canvas.msToBlob) {
// for IE
console.log("Function msToBlob found. Using existing function.");
- return new Promise((resolve: (arg0: any) => void) => {
- resolve(canvas.msToBlob());
- });
+ return Promise.resolve(canvas.msToBlob());
} else {
// other browsers ** this isn't currently working **
console.log("Function msToBlob not found. Using custom function.");
@@ -792,14 +686,12 @@ export default class DigitalBadge extends TeamsBaseComponent<
let promise: Promise = new Promise(
(resolve: any, _reject: any) => {
const canvas: any = document.getElementById("profileCanvas");
- const canvasDownload: any = document.getElementById(
- "profileCanvasDownload"
- );
+ const canvasDownload: any = document.getElementById("profileCanvasDownload");
const context = canvas.getContext("2d");
const contextDownload = canvasDownload.getContext("2d");
const profileImageObj: HTMLImageElement = new Image();
const badgeImageObj: HTMLImageElement = new Image();
- profileImageObj.src = profileImage.url;
+ profileImageObj.src = profileImage.url;
badgeImageObj.src = this.state.imageURL;
profileImageObj.onload = () => {
context.drawImage(
@@ -834,21 +726,19 @@ export default class DigitalBadge extends TeamsBaseComponent<
let promise: Promise = new Promise(
(resolve: any, _reject: any) => {
const canvas: any = document.getElementById("profileCanvas");
- const canvasDownload: any = document.getElementById(
- "profileCanvasDownload"
- );
+ const canvasDownload: any = document.getElementById("profileCanvasDownload");
const context = canvas.getContext("2d");
const contextDownload = canvasDownload.getContext("2d");
const profileImageObj: HTMLImageElement = new Image();
const badgeImageObj: HTMLImageElement = new Image();
profileImage.width = 100;
- profileImage.url = "../assets/images/noimage.png";
+ profileImage.url = "../assets/images/noimage.png";
this.setState({
profileImage: profileImage,
});
profileImageObj.src = require("../assets/images/noimage.png");
//To avoid CORS issue in CDN enabled tenants
- profileImageObj.crossOrigin= "Anonymous";
+ profileImageObj.crossOrigin = "Anonymous";
badgeImageObj.src = this.state.imageURL;
profileImageObj.onload = () => {
context.font = "32px Arial";
@@ -929,7 +819,6 @@ export default class DigitalBadge extends TeamsBaseComponent<
if (canvasDownload.msToBlob) {
// for IE
- let blob = canvasDownload.msToBlob();
this.setState({ downloadText: LocaleStrings.DownloadedButtonText });
} else {
// other browsers
@@ -950,6 +839,7 @@ export default class DigitalBadge extends TeamsBaseComponent<
public onUserAcceptance(): void {
this.setState({
hasAccepted: true,
+ digitalBadgeScreen: strings.digitalBadgeScreen2
});
this.getAllBadgeImages();
}
@@ -966,7 +856,7 @@ export default class DigitalBadge extends TeamsBaseComponent<
.api("me/photo/$value")
.version("v1.0")
.header("Content-Type", "image/jpeg")
- .put(blob, (errDb, _res, rawresponse) => {
+ .put(blob, (errDb: any, _res: any) => {
if (!errDb) {
resolve(_res);
}
@@ -997,10 +887,10 @@ export default class DigitalBadge extends TeamsBaseComponent<
.version("v1.0")
.headers({ "Content-Type": "blob", responseType: "blob" })
.get()
- .then((data) => {
+ .then((data: any) => {
resolve(data);
})
- .catch((errDb) => {
+ .catch((errDb: any) => {
reject(errDb);
});
});
@@ -1020,7 +910,7 @@ export default class DigitalBadge extends TeamsBaseComponent<
.version("v1.0")
.headers({ "Content-Type": "blob", responseType: "blob" })
.get()
- .then((data) => {
+ .then((data: any) => {
resolve(data);
});
});
@@ -1029,22 +919,20 @@ export default class DigitalBadge extends TeamsBaseComponent<
return photoPromise;
}
- public showUserInformation(_upn1: string) {
+ //Get and Process Profile photo data and update Canvas Elements.
+ public showUserInformation() {
let currentProfileImageObj: IProfileImage = { url: "", width: 0 };
this.getgraphMyPhotoBitsUrl()
.then((blob) => {
let blobUrl = URL.createObjectURL(blob);
currentProfileImageObj.url = blobUrl;
- $("#photoStuff").attr("src", blobUrl);
+ document.querySelector("#photoStuff")?.setAttribute("src", blobUrl);
currentProfileImageObj.url = blobUrl;
})
- .then((_asd) => {
+ .then(() => {
this.getgraphMyPhotoApiUrl().then((json) => {
currentProfileImageObj.width = json.width;
- this.setState({
- profileImage: currentProfileImageObj,
- });
- this.forceUpdate();
+ this.setState({ profileImage: currentProfileImageObj });
this._onRenderCanvas(currentProfileImageObj);
});
})
@@ -1059,7 +947,7 @@ export default class DigitalBadge extends TeamsBaseComponent<
let queryParams = { upn: "", tenantId: "" };
alert("Request query string params: " + location.search);
location.search
- .substr(1)
+ .substring(1)
.split("&")
.forEach((item) => {
let s = item.split("="),
diff --git a/src/webparts/clbHome/components/EmployeeView.tsx b/src/webparts/clbHome/components/EmployeeView.tsx
index 29b9b501..07356adb 100644
--- a/src/webparts/clbHome/components/EmployeeView.tsx
+++ b/src/webparts/clbHome/components/EmployeeView.tsx
@@ -4,7 +4,7 @@ import Sidebar from '../components/Sidebar';
import { WebPartContext } from '@microsoft/sp-webpart-base';
import '../scss/Employeeview.scss';
import * as LocaleStrings from 'ClbHomeWebPartStrings';
-
+import * as strings from "../constants/strings";
interface EmployeeViewState {
}
@@ -13,6 +13,8 @@ interface EmployeeViewProps {
context: WebPartContext;
onClickCancel: () => void;
siteUrl: string;
+ appTitle: string;
+ currentThemeName?: string;
}
export default class EmployeeView extends Component<
@@ -24,8 +26,9 @@ export default class EmployeeView extends Component<
}
public render() {
+ const isDarkOrContrastTheme = this.props.currentThemeName === strings.themeDarkMode || this.props.currentThemeName === strings.themeContrastMode;
return (
-
+
{ this.props.onClickCancel(); }}
- title={LocaleStrings.CMPBreadcrumbLabel}
+ role="button"
+ tabIndex={0}
+ onKeyDown={(evt: any) => { if (evt.key === strings.stringEnter) this.props.onClickCancel(); }}
+ aria-label={this.props.appTitle}
>
- {LocaleStrings.CMPBreadcrumbLabel}
+
+ {this.props.appTitle}
+
{LocaleStrings.ChampionLeaderBoardLabel}
@@ -52,6 +61,7 @@ export default class EmployeeView extends Component<
siteUrl={this.props.siteUrl}
context={this.props.context}
type={""}
+ currentThemeName={this.props.currentThemeName}
/>
diff --git a/src/webparts/clbHome/components/EventsChart.tsx b/src/webparts/clbHome/components/EventsChart.tsx
new file mode 100644
index 00000000..650600fc
--- /dev/null
+++ b/src/webparts/clbHome/components/EventsChart.tsx
@@ -0,0 +1,264 @@
+import * as LocaleStrings from 'ClbHomeWebPartStrings';
+import * as React from 'react';
+import * as stringsConstants from '../constants/strings';
+import commonServices from '../Common/CommonServices';
+import styles from '../scss/ChampionReport.module.scss';
+import { Chart } from 'chart.js';
+import { ChartControl, ChartType } from '@pnp/spfx-controls-react/lib/ChartControl';
+import { Component } from 'react';
+import { WebPartContext } from '@microsoft/sp-webpart-base';
+import '../scss/Champions.scss';
+
+// Common Services Object
+let commonServiceManager: commonServices;
+
+// Vertical Bar Chart Variables and Values
+const verticalChartColor: any = ['#02A5F2', '#FFBA02', '#888686', '#5BBB02', '#FF4F17', '#02A5F2', '#FFBA02', '#888686', '#5BBB02', '#FF4F17'];
+let chartLabelLength: number;
+let chartFontSize: number;
+let chartStepValue: number;
+
+export interface EventsChartProps {
+ context: WebPartContext;
+ siteUrl: string;
+ callBack?: Function;
+ filteredAllEvents: Array;
+ parentComponent: string;
+ selectedMemberID: string;
+ updateEventsListHeight?: Function;
+ currentThemeName?: string;
+}
+
+export interface EventsChartState {
+ topEventTypesChartdata: Chart.ChartData;
+ isDesktop: boolean;
+}
+
+export default class EventsChart extends Component {
+ private barChartRef: React.RefObject;
+ constructor(props: any) {
+ super(props);
+ this.barChartRef = React.createRef();
+
+ // States
+ this.state = {
+ topEventTypesChartdata: {},
+ isDesktop: true
+ };
+
+ // Create object for CommonServices class
+ commonServiceManager = new commonServices(
+ this.props.context,
+ this.props.siteUrl
+ );
+
+ }
+ // Method to load top 10 events for chart control
+ public componentDidMount() {
+ // Adding window resize event listener while mounting the component
+ window.addEventListener("resize", this.resize.bind(this));
+ this.resize();
+ // Assign appropriate values to the chart variables
+ chartLabelLength = this.state.isDesktop ? 14 : 8;
+ chartFontSize = this.state.isDesktop ? 14 : 12;
+ chartStepValue = this.state.isDesktop ? 5 : 10;
+
+ this.loadTopEvents(this.props.selectedMemberID);
+ }
+
+ // Set the state object for screen size
+ resize = () => {
+ this.setState({
+ isDesktop: this.props.parentComponent === stringsConstants.SidebarLabel ? ((window.innerWidth > 745 && window.innerWidth < 992)
+ || (window.innerWidth > 1092)) :
+ this.props.parentComponent === stringsConstants.ChampionReportLabel ? ((window.innerWidth > 540 && window.innerWidth <= 767)
+ || (window.innerWidth > 991)) : true
+ });
+ this.props.parentComponent === stringsConstants.ChampionReportLabel && this.props.updateEventsListHeight(this.barChartRef?.current.getElementsByTagName("div")[1].clientHeight + "px");
+ };
+
+ // Before unmounting, remove event listener
+ componentWillUnmount() {
+ window.removeEventListener("resize", this.resize.bind(this));
+ }
+
+ // This method will be called whenever there is an update to the component
+ public componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any) {
+
+ if (prevProps.selectedMemberID !== this.props.selectedMemberID ||
+ prevProps.filteredAllEvents !== this.props.filteredAllEvents) {
+ this.loadTopEvents(this.props.selectedMemberID);
+ }
+ if (prevState.isDesktop !== this.state.isDesktop) {
+ chartLabelLength = this.state.isDesktop ? 14 : 8;
+ chartFontSize = this.state.isDesktop ? 14 : 12;
+ chartStepValue = this.state.isDesktop ? 5 : 10;
+ }
+ }
+
+
+ // Get data for top 10 events
+ private async loadTopEvents(selectedChampion: string) {
+ try {
+ let arrLabels: string[] = [];
+ let arrData: number[] = [];
+ let topEventsArray: any[] = [];
+ let topEvents: any[] = [];
+ this.setState({
+ topEventTypesChartdata: {}
+ });
+ if (selectedChampion === stringsConstants.AllLabel) {
+ if (this.props.filteredAllEvents.length > 0) {
+ let organizedEvents = commonServiceManager.groupBy(this.props.filteredAllEvents, (item: any) => item.EventName);
+
+ // count the number of events for each event type
+ organizedEvents.forEach((event) => {
+ let totalEvents: number = event.length;
+
+ //Push the metrics of each event into an array.
+ topEventsArray.push({
+ Title: event[0].EventName,
+ Count: totalEvents
+ });
+ });
+
+ //Sort by number of events
+ topEventsArray.sort((a, b) => {
+ if (a.Count < b.Count) return 1;
+ if (a.Count > b.Count) return -1;
+ });
+
+ //get Top 10 Events
+ topEvents = topEventsArray.filter((item, idx) => idx < stringsConstants.ChartEventsLimit).map(item => { return item; });
+
+ if (topEvents.length > 0) {
+ //Loop through top events and add the labels and data for the chart display
+ topEvents.forEach(element => {
+ arrLabels.push(element.Title);
+ arrData.push(element.Count);
+ });
+ }
+ }
+ } else {
+ if (this.props.filteredAllEvents.length > 0) {
+
+ let championEvents = this.props.filteredAllEvents.filter((item) => item.MemberId === selectedChampion);
+ if (championEvents.length > 0) {
+ let organizedEvents = commonServiceManager.groupBy(championEvents, (item: any) => item.EventName);
+
+ //count the number of events for each event type
+ organizedEvents.forEach((event) => {
+ let totalEvents: number = event.length;
+
+ //Push the metrics of each event into an array.
+ topEventsArray.push({
+ Title: event[0].EventName,
+ Count: totalEvents
+ });
+ });
+
+ //Sort by number of events
+ topEventsArray.sort((a, b) => {
+ if (a.Count < b.Count) return 1;
+ if (a.Count > b.Count) return -1;
+ });
+
+ //get Top 10 Events
+ topEvents = topEventsArray.filter((item, idx) => idx < stringsConstants.ChartEventsLimit).map(item => { return item; });
+
+ if (topEvents.length > 0) {
+ //Loop through top events and add the labels and data for the chart display
+ topEvents.forEach(element => {
+ arrLabels.push(element.Title);
+ arrData.push(element.Count);
+ });
+ }
+ }
+ }
+ }
+ this.setState({
+ topEventTypesChartdata: {
+ labels: arrLabels,
+ datasets: [{
+ label: '',
+ data: arrData,
+ backgroundColor: verticalChartColor,
+ fill: false
+ }]
+ },
+ });
+ //Resetting the state to render the chart data with current state value
+ setTimeout(() => {
+ this.setState({
+ topEventTypesChartdata: this.state.topEventTypesChartdata,
+ });
+ }, 10);
+ }
+ catch (error) {
+ console.error("CMP_EventsChart_loadTopEvents \n", error);
+ }
+ }
+
+ // Main render method
+ public render() {
+ // To determine whether the component is called from sidebar or not
+ const isSidebar = this.props.parentComponent === stringsConstants.SidebarLabel;
+ const isDarkOrContrastTheme = this.props.currentThemeName === stringsConstants.themeDarkMode || this.props.currentThemeName === stringsConstants.themeContrastMode;
+ // Options for vertical bar chart
+ const verticalChartOptions = {
+ legend: {
+ labels: {
+ boxWidth: 0,
+ }
+ },
+ scales: {
+ yAxes: [{
+ stacked: true,
+ ticks: {
+ fontColor: isDarkOrContrastTheme ? "#FFFFFF" : "#020000",
+ fontSize: chartFontSize,
+ tooltips: true,
+ stepSize: chartStepValue,
+ callback: (label: string) => {
+ if (label.length > chartLabelLength) {
+ return label.slice(0, chartLabelLength) + '...';
+ } else {
+ return label;
+ }
+ }
+ }
+ }],
+ xAxes: [{
+ stacked: true,
+ ticks: {
+ fontColor: isDarkOrContrastTheme ? "#FFFFFF" : "#020000",
+ fontSize: chartFontSize,
+ stepSize: chartStepValue,
+ tooltips: true,
+ callback: (label: string) => {
+ if (label.length > chartLabelLength) {
+ return label.slice(0, chartLabelLength) + '...';
+ } else {
+ return label;
+ }
+ }
+ }
+ }]
+ },
+ };
+ return (
+
+
+
{LocaleStrings.EventChartLabel}
+
+
+
+ );
+ }
+}
diff --git a/src/webparts/clbHome/components/Header.tsx b/src/webparts/clbHome/components/Header.tsx
index 97351927..d12e99cd 100644
--- a/src/webparts/clbHome/components/Header.tsx
+++ b/src/webparts/clbHome/components/Header.tsx
@@ -1,8 +1,11 @@
-import { DirectionalHint, TooltipHost } from '@fluentui/react';
+import { TooltipHost } from '@fluentui/react';
import "bootstrap/dist/css/bootstrap.min.css";
import * as LocaleStrings from 'ClbHomeWebPartStrings';
-import { Callout, Link, Text } from 'office-ui-fabric-react';
import { Icon } from 'office-ui-fabric-react/lib/Icon';
+import {
+ Popover, PopoverSurface,
+ PopoverTrigger, Link, Text
+} from '@fluentui/react-components';
import React, { Component } from "react";
import Navbar from "react-bootstrap/Navbar";
import * as Strings from '../constants/strings';
@@ -15,10 +18,11 @@ interface IHeaderProps {
showSearch: boolean;
clickcallback: () => void; //will redirects to home
logoImageURL: string;
+ appTitle: string;
+ currentThemeName?: string;
}
interface HeaderState {
isCalloutVisible: boolean;
-
}
export default class Header extends Component {
constructor(_props: any) {
@@ -35,11 +39,9 @@ export default class Header extends Component {
this.setState({ isCalloutVisible: !this.state.isCalloutVisible });
}
public render() {
- const buttonId = 'callout-button';
- const labelId = 'callout-label';
- const descriptionId = 'callout-description';
+ const isDarkOrContrastTheme = this.props.currentThemeName === Strings.themeDarkMode || this.props.currentThemeName === Strings.themeContrastMode;
return (
-
+
{
onClick={this.homeRedirect}
title={LocaleStrings.AppLogoToolTip}
/>
-
- {LocaleStrings.AppHeaderTitleLabel}
+
+ {this.props.appTitle}
-
-
-
-
- {this.state.isCalloutVisible && (
-
+
+ { if (evt.key === Strings.stringEnter) this.toggleIsCalloutVisible() }}
+ aria-label={LocaleStrings.MoreInfoToolTip}
+ tabIndex={0}
+ role="button"
+ onClick={this.toggleIsCalloutVisible}
+ className={styles.infoIconWrapper}
>
-
- {LocaleStrings.AboutHeaderLabel}
-
-
- {LocaleStrings.AboutContentLabel}
-
-
- {LocaleStrings.AdditionalResourcesHeaderLabel}
-
-
- {LocaleStrings.AdditionalResourcesContentLabel}
-
-
- {LocaleStrings.M365ChampionCommunityLinkLabel}
-
-
- {LocaleStrings.DrivingAdoptionLinkLabel}
-
-
- ----
-
-
- {LocaleStrings.CurrentVersionLabel} {packageSolution.solution.version}
-
-
- {LocaleStrings.LatestVersionLabel} {LocaleStrings.CMPGitHubLinkLabel}
-
-
- ----
-
-
- {LocaleStrings.VisitLabel}
-
-
- {LocaleStrings.OverviewLabel} {LocaleStrings.MSAdoptionHubLinkLabel}
-
-
- {LocaleStrings.DocumentationLabel} {LocaleStrings.CMPGitHubLinkLabel}
-
-
- )}
-
+
+
+
+
+
+
+
+ {LocaleStrings.AboutHeaderLabel} {this.props.appTitle}:
+
+
+ {this.props.appTitle} {LocaleStrings.AboutContentLabel}
+
+
+ {LocaleStrings.AdditionalResourcesHeaderLabel}
+
+
+ {LocaleStrings.AdditionalResourcesContentLabel}
+
+
+ {LocaleStrings.M365ChampionCommunityLinkLabel}
+
+
+ {LocaleStrings.DrivingAdoptionLinkLabel}
+
+
+ ----
+
+
+ {LocaleStrings.CurrentVersionLabel} {packageSolution.solution.version}
+
+
+ {LocaleStrings.LatestVersionLabel} {LocaleStrings.CMPGitHubLinkLabel}
+
+
+ ----
+
+
+ {LocaleStrings.VisitLabel}
+
+
+ {LocaleStrings.OverviewLabel} {LocaleStrings.MSAdoptionHubLinkLabel}
+
+
+ {LocaleStrings.DocumentationLabel} {LocaleStrings.CMPGitHubLinkLabel}
+
+
+
-
+
);
}
}
diff --git a/src/webparts/clbHome/components/ManageApprovals.tsx b/src/webparts/clbHome/components/ManageApprovals.tsx
index 1523057e..87902c58 100644
--- a/src/webparts/clbHome/components/ManageApprovals.tsx
+++ b/src/webparts/clbHome/components/ManageApprovals.tsx
@@ -1,4 +1,4 @@
-import { IPivotItemProps, Pivot, PivotItem, PivotLinkFormat } from '@fluentui/react';
+import { IPivotItemProps, Pivot, PivotItem } from '@fluentui/react';
import { WebPartContext } from "@microsoft/sp-webpart-base";
import * as LocaleStrings from 'ClbHomeWebPartStrings';
import React, { Component } from 'react';
@@ -7,6 +7,7 @@ import styles from "../scss/ManageApprovals.module.scss";
import ApproveChampion from './ApproveChampion';
import ChampionsActivities from './ChampionsActivities';
import ManageConfigSettings from './ManageConfigSettings';
+import * as stringsConstants from "../constants/strings";
//declaring common services object
let commonServiceManager: commonServices;
@@ -16,10 +17,14 @@ export interface IManageApprovalsProps {
onClickBack: Function;
isPendingChampionApproval: boolean;
isPendingEventApproval: boolean;
+ appTitle: string;
+ updateAppTitle: Function;
+ currentThemeName?: string;
}
export interface IManageApprovalsState {
isPendingChampionApproval: boolean;
isPendingEventApproval: boolean;
+ appTitle: string;
}
export default class ManageApprovals extends Component
{
@@ -28,6 +33,7 @@ export default class ManageApprovals extends Component, prevState: Readonly, snapshot?: any): void {
+ //updating state of the parent component 'ClbHome" to show the new app title in app header and breadcrumb
+ if (prevState.appTitle !== this.state.appTitle) {
+ this.props.updateAppTitle({
+ appTitle: this.state.appTitle
+ });
+ }
+ }
+
_customRenderer(
link?: IPivotItemProps,
defaultRenderer?: (link?: IPivotItemProps) => JSX.Element | null,
@@ -72,61 +89,76 @@ export default class ManageApprovals extends Component
+
{ this.props.onClickBack(); }}
- title={LocaleStrings.CMPBreadcrumbLabel}
+ role="button"
+ tabIndex={0}
+ onKeyDown={(evt: any) => { if (evt.key === stringsConstants.stringEnter) this.props.onClickBack(); }}
+ aria-label={this.props.appTitle}
>
- {LocaleStrings.CMPBreadcrumbLabel}
+
+ {this.props.appTitle}
+
{LocaleStrings.AdminTasksLabel}
-
+
+
+
-
+
+
+
-
+
+
+
diff --git a/src/webparts/clbHome/components/ManageConfigSettings.tsx b/src/webparts/clbHome/components/ManageConfigSettings.tsx
index 6a3aab15..bbcb67f4 100644
--- a/src/webparts/clbHome/components/ManageConfigSettings.tsx
+++ b/src/webparts/clbHome/components/ManageConfigSettings.tsx
@@ -14,6 +14,8 @@ import { TooltipHost } from '@fluentui/react/lib/Tooltip';
import { Icon } from '@fluentui/react/lib/Icon';
import { Label } from "@fluentui/react/lib/Label";
import { Spinner, SpinnerSize } from '@fluentui/react/lib/Spinner';
+import { ITextFieldProps, TextField } from '@fluentui/react/lib/TextField';
+import { TOTBreadcrumbLabel } from 'ClbHomeWebPartStrings';
//global variables
let commonServiceManager: commonServices;
@@ -21,6 +23,8 @@ let commonServiceManager: commonServices;
export interface IManageConfigSettingsProps {
context?: WebPartContext;
siteUrl: string;
+ appTitle: string;
+ updateAppTitle: Function;
}
export interface IConfigList {
@@ -37,6 +41,8 @@ export interface IManageConfigSettingsState {
updatedSettings: Array;
memberListColumns: Array;
showSpinner: boolean;
+ appTitle: string;
+ appTitleError: boolean;
}
export default class ManageConfigSettings extends React.Component
@@ -50,7 +56,9 @@ export default class ManageConfigSettings extends React.Component
configListSettings: [],
updatedSettings: [],
memberListColumns: [],
- showSpinner: false
+ showSpinner: false,
+ appTitle: this.props.appTitle,
+ appTitleError: false
};
//Bind Methods
@@ -159,38 +167,84 @@ export default class ManageConfigSettings extends React.Component
});
}
+ //on change event for App Title field
+ private onAppTitleChange(_eve: any, newValue: string) {
+ //update the state with new value
+ this.setState({
+ showSuccess: false,
+ showError: false,
+ appTitleError: false,
+ appTitle: newValue
+ })
+ }
+
//Update the selected settings into the Config list on click of save
private async saveConfigSettings() {
- if (this.state.updatedSettings.length > 0) {
- this.setState({ showSpinner: true });
- commonServiceManager
- .updateMultipleItemsWithDifferentValues(
- stringsConstants.ConfigList,
- this.state.updatedSettings
- ).then(() => {
- this.setState({ showSuccess: true, updatedSettings: [], showSpinner: false });
- }).catch((error) => {
- console.error("CMP_ManageConfigSettings_saveConfigSettings \n", error);
- this.setState({
- showError: true,
- errorMessage:
- stringsConstants.CMPErrorMessage +
- " while saving the selection. Below are the details: \n" +
- JSON.stringify(error),
- updatedSettings: [],
- showSpinner: false
+ let newTitle = this.state.appTitle.trim();
+ this.setState({
+ showError: false,
+ showSuccess: false,
+ appTitleError: false,
+ errorMessage: "",
+ appTitle: newTitle
+ })
+
+ if (newTitle === "" || newTitle === undefined) {
+ this.setState({
+ appTitleError: true
+ })
+ } else {
+ //updating the AppTitle entry in the config list, if it is changed
+ if (this.props.appTitle !== newTitle) {
+ let itemID = this.state.configListSettings.filter((item) => {
+ return item.Title === stringsConstants.AppTitle;
+ })
+ this.state.updatedSettings.push({
+ id: itemID[0].ID,
+ value: { Value: newTitle }
+ })
+ }
+
+ if (this.state.updatedSettings.length > 0) {
+ this.setState({ showSpinner: true });
+ commonServiceManager
+ .updateMultipleItemsWithDifferentValues(
+ stringsConstants.ConfigList,
+ this.state.updatedSettings
+ ).then(() => {
+ this.setState({ showSuccess: true, updatedSettings: [], showSpinner: false });
+ //update the state of Parent Component "Manage Approvals" to show the new app title in the app header and breadcrumb
+ if (this.props.appTitle !== newTitle) {
+ this.props.updateAppTitle({
+ appTitle: newTitle
+ });
+ }
+ }).catch((error) => {
+ console.error("CMP_ManageConfigSettings_saveConfigSettings \n", error);
+ this.setState({
+ showError: true,
+ errorMessage:
+ stringsConstants.CMPErrorMessage +
+ " while saving the selection. Below are the details: \n" +
+ JSON.stringify(error),
+ updatedSettings: [],
+ showSpinner: false
+ });
});
+ }
+ else {
+ this.setState({
+ showSuccess: true,
+ updatedSettings: []
});
- }
- else {
- this.setState({ showSuccess: true });
+ }
}
}
//Tooltip for info Icon
private iconWithTooltip(iconName: string, tooltipContent: string, className: string) {
return (
-
+
}
+
{this.state.configListSettings.length > 0 &&
<>
{this.state.showSuccess && (
-