• /
  • Log in
  • Free account

Present an end test confirmation modal

Course

This lesson is part of a course that teaches you how to build a New Relic One application from the ground up. If you haven't already, check out the course introduction.

Each lesson in the course builds upon the last, so make sure you've completed the last lesson, Persist the selected version, before starting this one.

In this tutorial, you're building an A/B test application. The application surfaces data about an ongoing A/B test on your website, which you then use to decide which page design version is most effective at engaging users. As part of that overarching goal, you're building a section which allows you to end the test by deciding a winner of the experiment:

First version of your end test section

Unfortunately, there are a few issues with the code and design for this section. By the end of this course, pressing End test will tell your website's backend server that every customer should see the version selected here. This is destructive behavior because it makes an irreversible change to your website. To account for the desctructiveness of pressing End test, you need to modify some features of your application:

  • Make the button look important to catch your eye
  • Prompt yourself with a confirmation message before ending the test to ensure you don't end it prematurely

Show and hide your confirmation modal

Step 1 of 12

Change to the present-confirmation-modal directory of the coursework repository:

bash
$
cd nru-programmability-course/present-confirmation-modal

This directory contains the code your application should have at this point in the course. By navigating to the correct directory at the start of each lesson, you leave your custom code behind, thereby protecting yourself from carrying incorrect code from one lesson to the next.

Step 2 of 12

In nerdlets/ab-test-nerdlet/end-test.js, update the Button to use the DESTRUCTIVE styling:

import React from 'react';
import {
Button,
Grid,
GridItem,
HeadingText,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}
nerdlets/ab-test-nerdlet/end-test.js

Tip

Read more about Button and its props on the New Relic developer site.

Step 3 of 12

Navigate to the root of your Nerdpack at nru-programmability-course/present-confirmation-modal/ab-test.

Step 4 of 12

Generate a new UUID for your Nerdpack:

bash
$
nr1 nerdpack:uuid -gf

Because you cloned the coursework repository that contained an existing Nerdpack, you need to generate your own unique identifier. This UUID maps your Nerdpack to your New Relic account.

Step 5 of 12

Serve your application locally:

bash
$
nr1 nerdpack:serve
Step 6 of 12

View your application:

Second version of your end test section

Now you've styled your button to convey its destructive consequences, but that's not enough to prevent you from accidentally clicking it. Next, you create a shield for your website's backend. This extra layer of protection requires you to confirm that you intend to end the test before actually doing so.

Step 7 of 12

Add a Modal to EndTestButton:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}
nerdlets/ab-test-nerdlet/end-test.js

Your new modal contains a heading, a confirmation message, the winning design version, and two buttons. You'll explore some of these components later in this course.

With your nerdpack served locally, view your application to see your new Modal:

End test modal

Tip

Remember, while your server is running, it will update automatically when you save your code.

The modal looks great, but it has three issues:

  • It was present before you clicked End test
  • You can't dismiss it
  • It always says you selected "Version A", even if you didn't

In the following steps, you'll correct all three of these issues.

Step 8 of 12

In EndTestButton, initialize state with a value for modalHidden:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor(props) {
super(props);
this.state = {
modalHidden: true,
}
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}
nerdlets/ab-test-nerdlet/end-test.js

modalHidden determines whether or not to hide the modal. The default value of modalHidden is true because you only want to show the modal when you select End test.

Step 9 of 12

Supply modalHidden to the Modal:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal hidden={this.state.modalHidden}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}
nerdlets/ab-test-nerdlet/end-test.js

First, you've created a constructor to accept component props. This provides your component access to the modalHidden prop that you passed in EndTestSection. Then you provide the value of modalHidden to the Modal component's hidden prop.

Tip

Read more about Modal and its props on the New Relic developer site.

Step 10 of 12

Add and bind two new methods to EndTestSection:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
closeModal() {
this.setState({ modalHidden: true });
}
showModal() {
this.setState({ modalHidden: false });
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal hidden={this.state.modalHidden}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}
nerdlets/ab-test-nerdlet/end-test.js

Use closeModal and showModal to close and show your modal, respectively, depending on how a user interacts with the modal.

Step 11 of 12

Show the modal when you click End test:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
closeModal() {
this.setState({ modalHidden: true });
}
showModal() {
this.setState({ modalHidden: false });
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}
nerdlets/ab-test-nerdlet/end-test.js

Here, you've supplied showModal() as the callback for the Button component's onClick event.

View your application where the modal is hidden by default. Click End test to see the modal.

Step 12 of 12

Close the modal from the Modal component's onClose callback and from the Yes, end test and No, continue test buttons:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
closeModal() {
this.setState({ modalHidden: true });
}
showModal() {
this.setState({ modalHidden: false });
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button onClick={this.closeModal}>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}
nerdlets/ab-test-nerdlet/end-test.js

View your application and click End test. The modal opens and displays your confirmation message. Close the modal by clicking X at the top right, either of its buttons, or even in the dark space to its left.

Notice that the modal says you chose "Version A", even if you choose "Version B". This is because "Version A" is hardcoded in the Modal text. Next, you'll make that dynamic.

Use the version you selected in your modal

Step 1 of 2

In EndTestSection, pass selectedVersion to the EndTestButton:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
closeModal() {
this.setState({ modalHidden: true });
}
showModal() {
this.setState({ modalHidden: false });
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button onClick={this.closeModal}>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton selectedVersion={this.state.selectedVersion}>End test</EndTestButton>
</GridItem>
</Grid>
}
}
nerdlets/ab-test-nerdlet/end-test.js

Now, you can access the selected version from the EndTestButton component's props.

Step 2 of 2

Use selectedVersion in your confirmation message:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
closeModal() {
this.setState({ modalHidden: true });
}
showModal() {
this.setState({ modalHidden: false });
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version {this.props.selectedVersion}</b>
</BlockText>
<Button onClick={this.closeModal}>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton selectedVersion={this.state.selectedVersion}>End test</EndTestButton>
</GridItem>
</Grid>
}
}
nerdlets/ab-test-nerdlet/end-test.js

View your application and select "Version B" from the menu. Click End test to see "Version B" in the confirmation modal:

The modal shows your selected version

When you're finished, stop serving your New Relic One application by pressing CTRL+C in the terminal window where you're serving your application.

Congratulations! You've done a lot of work and it shows in the usefulness of your application. You've created charts that show mocked data. You've organized your charts into a readable structure. You've added an interface for your users to interact with the test. Now, you need some real data. In the next lesson, you'll replace the mocked data in your charts with real data from your backend service.

Course

This lesson is part of a course that teaches you how to build a New Relic One application from the ground up. Continue on to the next lesson: Add NrqlQuery components to your nerdlet.

Create issueEdit page
Copyright © 2021 New Relic Inc.