Skip to content

Commit

Permalink
Showing 6 changed files with 302 additions and 19 deletions.
61 changes: 58 additions & 3 deletions client/src/Book.test.tsx
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import { AppConfigModel } from './models/ConfigModel';
import * as FetchConfig from './utils/FetchConfig';
import { runFakeTimers } from './utils/TestUtils';
import { generateTheme } from './utils/ThemeGenerator';
import * as renderer from 'react-test-renderer';
import { BOOKINGS_SPECIMEN_URL } from './utils/Constants';
import WarningBanner from './components/Book/WarningBanner';

@@ -56,7 +57,7 @@ describe('Book', () => {
expect(genericError.length).toBe(1);
});

it('should render header and bookings iframe when config is loaded', async () => {
it('should render header and bookings iframe when config is loaded and bookings link is not empty', async () => {
const mockBookingsUrl = 'https://example.org';
const fetchConfigSpy = jest.spyOn(FetchConfig, 'fetchConfig');
fetchConfigSpy.mockReturnValue(
@@ -91,12 +92,12 @@ describe('Book', () => {
expect(iframes.first().props().src).toBe(mockBookingsUrl);
});

it('should render warning banner if using specimen Bookings page', async () => {
it('should render header and no scheduling info when config is loaded and bookings link is empty', async () => {
const fetchConfigSpy = jest.spyOn(FetchConfig, 'fetchConfig');
fetchConfigSpy.mockReturnValue(
Promise.resolve({
communicationEndpoint: 'endpoint=test_endpoint;',
microsoftBookingsUrl: BOOKINGS_SPECIMEN_URL,
microsoftBookingsUrl: '',
chatEnabled: true,
screenShareEnabled: true,
companyName: '',
@@ -118,10 +119,64 @@ describe('Book', () => {
const iframes = book.find('iframe');
const warningBanner = book.find(WarningBanner);

expect(spinners.length).toBe(0);
expect(warningBanner.length).toBe(0);
expect(headers.length).toBe(1);
expect(iframes.length).toBe(0);
});

it('should render warning banner if using specimen Bookings page', async () => {
const fetchConfigSpy = jest.spyOn(FetchConfig, 'fetchConfig');
fetchConfigSpy.mockReturnValue(
Promise.resolve({
communicationEndpoint: 'endpoint=test_endpoint;',
microsoftBookingsUrl: BOOKINGS_SPECIMEN_URL,
chatEnabled: true,
screenShareEnabled: true,
companyName: '',
theme: generateTheme('#FFFFFF'),
waitingTitle: '',
waitingSubtitle: '',
logoUrl: ''
} as AppConfigModel)
);

const book = await mount(<Book />);

await runFakeTimers();
book.update();

const warningBanner = book.find(WarningBanner);

const spinners = book.find(Spinner);
const headers = book.find(Header);
const iframes = book.find('iframe');

expect(spinners.length).toBe(0);
expect(warningBanner.length).toBe(1);
expect(headers.length).toBe(1);
expect(iframes.length).toBe(1);
expect(iframes.first().props().src).toBe(BOOKINGS_SPECIMEN_URL);
});

it('should match snapshot when bookings link is empty', async () => {
const fetchConfigSpy = jest.spyOn(FetchConfig, 'fetchConfig');
fetchConfigSpy.mockReturnValue(
Promise.resolve({
communicationEndpoint: 'endpoint=test_endpoint;',
microsoftBookingsUrl: '',
chatEnabled: true,
screenShareEnabled: true,
companyName: '',
theme: generateTheme('#FFFFFF'),
waitingTitle: '',
waitingSubtitle: '',
logoUrl: ''
} as AppConfigModel)
);
const book = renderer.create(<Book />);
await runFakeTimers();

expect(book.toJSON()).toMatchSnapshot();
});
});
22 changes: 6 additions & 16 deletions client/src/Book.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { LayerHost, Spinner, Stack, ThemeProvider } from '@fluentui/react';
import { Spinner, Stack, ThemeProvider } from '@fluentui/react';
import { backgroundStyles, fullSizeStyles } from './styles/Common.styles';
import { embededIframeStyles } from './styles/Book.styles';
import { Header } from './Header';
import './styles/Common.css';
import { fetchConfig } from './utils/FetchConfig';
import { AppConfigModel } from './models/ConfigModel';
import { GenericError } from './components/GenericError';
import { useEffect, useState } from 'react';
import { BOOKINGS_SPECIMEN_URL } from './utils/Constants';
import WarningBanner from './components/Book/WarningBanner';

const PARENT_ID = 'BookMeetingSection';
import { BookingsPage } from './components/Book/BookingsPage';
import { NoSchedulingPage } from './components/Book/NoSchedulingPage';

export const Book = (): JSX.Element => {
const [config, setConfig] = useState<AppConfigModel | undefined>(undefined);
const [error, setError] = useState<any | undefined>(undefined);

const PARENT_ID = 'BookMeetingSection';

useEffect(() => {
const fetchData = async (): Promise<void> => {
try {
@@ -38,16 +37,7 @@ export const Book = (): JSX.Element => {
<ThemeProvider theme={config.theme} style={{ height: '100%' }}>
<Stack styles={backgroundStyles(config.theme)}>
<Header companyName={config.companyName} parentid={PARENT_ID} />
<LayerHost
id={PARENT_ID}
style={{
position: 'relative',
height: '100%'
}}
>
{config.microsoftBookingsUrl === BOOKINGS_SPECIMEN_URL ? <WarningBanner /> : <></>}
<iframe src={config.microsoftBookingsUrl} scrolling="yes" style={embededIframeStyles}></iframe>
</LayerHost>
{config.microsoftBookingsUrl ? <BookingsPage config={config} /> : <NoSchedulingPage config={config} />}
</Stack>
</ThemeProvider>
);
140 changes: 140 additions & 0 deletions client/src/__snapshots__/Book.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Book should match snapshot when bookings link is empty 1`] = `
<div
className="body-118"
style={
Object {
"height": "100%",
}
}
>
<div
className="ms-Stack css-119"
>
<div
className="ms-Stack css-120"
>
<div>
<button
aria-label="Menu Button"
className="ms-Button ms-Button--icon root-121"
data-is-focusable={true}
id="waffle-menu"
onClick={[Function]}
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
type="button"
>
<span
className="ms-Button-flexContainer flexContainer-122"
data-automationid="splitbuttonprimary"
>
<i
aria-hidden={true}
className="ms-Icon root-105 ms-Button-icon icon-124"
data-icon-name="Waffle"
style={
Object {
"fontFamily": undefined,
}
}
/>
</span>
</button>
</div>
<span
className="css-128"
>
</span>
</div>
<div
className="ms-Stack css-129"
>
<div
className="ms-Stack css-130"
>
<div
className="ms-Stack css-131"
>
<span
className="css-132"
>
No scheduling configured
</span>
<span
className="css-133"
>
This sample does not have a Microsoft Bookings page configured.
</span>
<span
className="css-134"
>
Frequently asked questions
</span>
<div
className="ms-Stack css-135"
>
<a
className="ms-Link root-136"
href="https://aka.ms/virtual-appointments-sample-bookings"
onClick={[Function]}
tabIndex={0}
target="_blank"
>
<div
className="ms-Stack css-137"
>
<div
className="ms-StackItem css-138"
style={
Object {
"fontFamily": "sf pro text",
"fontSize": ".9375rem",
"fontWeight": "400",
"letterSpacing": "-0.015rem",
"lineHeight": "1.25rem",
"paddingRight": ".5rem",
"textDecoration": "underline",
"verticalAlign": "bottom",
}
}
>
How do I change my Microsoft Bookings page URL?
</div>
<div
className="ms-StackItem css-138"
style={
Object {
"textDecoration": "none",
}
}
>
<span
style={
Object {
"alignItems": "center",
"display": "flex",
}
}
>
<i
aria-hidden={true}
className="root-105"
data-icon-name="OpenInNewWindow"
/>
</span>
</div>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
`;
29 changes: 29 additions & 0 deletions client/src/components/Book/BookingsPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { LayerHost } from '@fluentui/react';
import { BOOKINGS_SPECIMEN_URL } from '../../utils/Constants';
import WarningBanner from './WarningBanner';
import { AppConfigModel } from '../../models/ConfigModel';
import { embededIframeStyles } from '../../styles/Book.styles';

const PARENT_ID = 'BookMeetingSection';

interface BookingsPageProps {
config: AppConfigModel;
}

export const BookingsPage = (props: BookingsPageProps): JSX.Element => {
return (
<LayerHost
id={PARENT_ID}
style={{
position: 'relative',
height: '100%'
}}
>
{props.config.microsoftBookingsUrl === BOOKINGS_SPECIMEN_URL ? <WarningBanner /> : <></>}
<iframe src={props.config.microsoftBookingsUrl} scrolling="yes" style={embededIframeStyles}></iframe>
</LayerHost>
);
};
30 changes: 30 additions & 0 deletions client/src/components/Book/NoSchedulingPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import {
containerStyles,
fullScreenStyles,
innerContainer,
lineHeight22px,
lineHeight28px
} from '../../styles/Book.styles';
import { Stack, Text } from '@fluentui/react';
import { FrequentlyAskedQuestions } from '../FrequentlyAskedQuestions';
import { AppConfigModel } from '../../models/ConfigModel';

interface NoSchedulingPageProps {
config: AppConfigModel;
}

export const NoSchedulingPage = (props: NoSchedulingPageProps): JSX.Element => {
return (
<Stack styles={fullScreenStyles}>
<Stack horizontalAlign="center" styles={containerStyles(props.config.theme)} tokens={{ childrenGap: 15 }}>
<Stack styles={innerContainer}>
<Text styles={lineHeight28px}>No scheduling configured</Text>
<Text styles={lineHeight22px}>This sample does not have a Microsoft Bookings page configured.</Text>
<FrequentlyAskedQuestions />
</Stack>
</Stack>
</Stack>
);
};
39 changes: 39 additions & 0 deletions client/src/styles/Book.styles.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,47 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { PartialTheme, Theme } from '@fluentui/theme';

export const embededIframeStyles = {
width: '100%',
height: '100%',
border: '0px'
};

export const fullScreenStyles = {
root: {
width: '100%',
height: '100%'
}
};

export function containerStyles(theme: PartialTheme | Theme | undefined): any {
return {
root: {
maxWidth: '64rem',
width: '100%',
height: '100%',
display: 'flex',
margin: 'auto',
marginTop: '38px',
backgroundColor: 'white',
borderRadius: theme?.effects?.roundedCorner4
}
};
}

export const innerContainer = {
root: {
width: '600px',
marginTop: '200px'
}
};

export const lineHeight28px = {
root: { fontWeight: '600', fontSize: '20px', lineHeight: '28px' }
};

export const lineHeight22px = {
root: { fontWeight: '600', fontSize: '16px', lineHeight: '22px', marginBottom: '16px' }
};

0 comments on commit e422878

Please sign in to comment.