packages/storybook8/stories/Concepts/TeamsInterop/ComplianceBanner/snippets/ComplianceBanner.snippet.tsx (197 lines of code) (raw):

// ComplianceBanner.snippet.tsx import { Link, MessageBar } from '@fluentui/react'; import React, { ReactElement, useEffect, useRef, useState } from 'react'; export type ComplianceBannerProps = { callTranscribeState?: boolean; callRecordState?: boolean; }; type CachedComplianceBannerProps = { latest: ComplianceBannerProps; previous: ComplianceBannerProps; }; export const ComplianceBanner = (props: ComplianceBannerProps): JSX.Element => { const cachedProps = useRef<CachedComplianceBannerProps>({ latest: { callTranscribeState: false, callRecordState: false }, previous: { callTranscribeState: false, callRecordState: false } }); // Only update cached props if there is _some_ change in the latest props. // This ensures that state machine is only updated if there is an actual change in the props. if ( props.callRecordState !== cachedProps.current.latest.callRecordState || props.callTranscribeState !== cachedProps.current.latest.callTranscribeState ) { cachedProps.current = { latest: props, previous: cachedProps.current.latest }; } const variant = computeVariant( cachedProps.current.previous.callRecordState, cachedProps.current.previous.callTranscribeState, cachedProps.current.latest.callRecordState, cachedProps.current.latest.callTranscribeState ); return <DismissableMessageBar variant={variant} />; }; function DismissableMessageBar(props: { variant: number }): ReactElement { const { variant: newVariant } = props; const [variant, setVariant] = useState(0); // We drive the `MessageBar` indirectly via the `variant` state variable. // This allows the `onDismiss` handler to set the `variant` state to dismiss the `MessageBar`. // This means that when props change, this component renders *twice*: After the first render, this `useEffect` block // updates the value of `variant` state variable, which triggers a second render to update the message in the `MessageBar`. useEffect(() => { setVariant(newVariant); }, [newVariant, setVariant]); return variant === NO_STATE ? ( <></> ) : ( <MessageBar onDismiss={() => { setVariant(NO_STATE); }} dismissButtonAriaLabel="Close" > <BannerMessage variant={variant} /> </MessageBar> ); } const TRANSCRIPTION_STOPPED_STILL_RECORDING = 1; const RECORDING_STOPPED_STILL_TRANSCRIBING = 2; const RECORDING_AND_TRANSCRIPTION_STOPPED = 3; const RECORDING_AND_TRANSCRIPTION_STARTED = 4; const TRANSCRIPTION_STARTED = 5; const RECORDING_STOPPED = 6; const RECORDING_STARTED = 7; const TRANSCRIPTION_STOPPED = 8; const NO_STATE = 0; function computeVariant( previousCallRecordState: boolean | undefined, previousCallTranscribeState: boolean | undefined, callRecordState: boolean | undefined, callTranscribeState: boolean | undefined ): number { if (previousCallRecordState && previousCallTranscribeState) { if (callRecordState && !callTranscribeState) { return TRANSCRIPTION_STOPPED_STILL_RECORDING; } else if (!callRecordState && callTranscribeState) { return RECORDING_STOPPED_STILL_TRANSCRIBING; } else if (!callRecordState && !callTranscribeState) { return RECORDING_AND_TRANSCRIPTION_STOPPED; } else { return NO_STATE; } } else if (previousCallRecordState && !previousCallTranscribeState) { if (callRecordState && callTranscribeState) { return RECORDING_AND_TRANSCRIPTION_STARTED; } else if (!callRecordState && callTranscribeState) { return TRANSCRIPTION_STARTED; } else if (!callRecordState && !callTranscribeState) { return RECORDING_STOPPED; } else { return NO_STATE; } } else if (!previousCallRecordState && previousCallTranscribeState) { if (callRecordState && callTranscribeState) { return RECORDING_AND_TRANSCRIPTION_STARTED; } else if (!callRecordState && callTranscribeState) { return RECORDING_STARTED; } else if (!callRecordState && !callTranscribeState) { return TRANSCRIPTION_STOPPED; } else { return NO_STATE; } } else if (!previousCallRecordState && !previousCallTranscribeState) { if (callRecordState && callTranscribeState) { return RECORDING_AND_TRANSCRIPTION_STARTED; } else if (callRecordState && !callTranscribeState) { return RECORDING_STARTED; } else if (!callRecordState && callTranscribeState) { return TRANSCRIPTION_STARTED; } else { return NO_STATE; } } return NO_STATE; } function BannerMessage(props: { variant: number }): JSX.Element { switch (props.variant) { case TRANSCRIPTION_STOPPED_STILL_RECORDING: return ( <> <b>Transcription has stopped.</b> You are now only recording this meeting. <PrivacyPolicy /> </> ); case RECORDING_STOPPED_STILL_TRANSCRIBING: return ( <> <b>Recording has stopped.</b> You are now only transcribing this meeting. <PrivacyPolicy /> </> ); case RECORDING_AND_TRANSCRIPTION_STOPPED: return ( <> <b>Recording and transcription are being saved. </b> Recording and transcription have stopped. <LearnMore /> </> ); case RECORDING_AND_TRANSCRIPTION_STARTED: return ( <> <b>Recording and transcription have started.</b> By joining, you are giving consent for this meeting to be transcribed. <PrivacyPolicy /> </> ); case TRANSCRIPTION_STARTED: return ( <> <b>Transcription has started.</b> By joining, you are giving consent for this meeting to be transcribed. <PrivacyPolicy /> </> ); case RECORDING_STOPPED: return ( <> <b>Recording is being saved.</b> Recording has stopped. <LearnMore /> </> ); case RECORDING_STARTED: return ( <> <b>Recording has started.</b> By joining, you are giving consent for this meeting to be transcribed. <PrivacyPolicy /> </> ); case TRANSCRIPTION_STOPPED: return ( <> <b>Transcription is being saved.</b> Transcription has stopped. <LearnMore /> </> ); } return <></>; } function PrivacyPolicy(): JSX.Element { return ( <Link href="https://privacy.microsoft.com/privacystatement#mainnoticetoendusersmodule" target="_blank" underline> Privacy policy </Link> ); } function LearnMore(): JSX.Element { return ( <Link href="https://support.microsoft.com/office/record-a-meeting-in-teams-34dfbe7f-b07d-4a27-b4c6-de62f1348c24" target="_blank" underline > Learn more </Link> ); }