Dica
Esta lição faz parte de um curso que ensina como construir um aplicativo New Relic do zero. Se ainda não o fez, confira a Visão Geral.
Cada lição do curso se baseia na anterior, portanto, certifique-se de ter concluído a última lição e persistir na versão selecionada antes de iniciar esta.
Neste tutorial, você está construindo um aplicativo de teste A/B. O aplicativo exibe dados sobre um teste A/B em andamento em seu site, que você usa para decidir qual versão de design de página é mais eficaz para envolver o usuário. Como parte desse objetivo abrangente, você está construindo uma seção que permite encerrar o teste decidindo o vencedor do experimento.
Infelizmente, existem alguns problemas com o código e o design desta seção. Ao final deste curso, pressionar End test informará ao servidor backend do seu site que todos os clientes deverão ver a versão selecionada aqui. Este é um comportamento destrutivo porque causa uma alteração irreversível no seu site. Para dar conta da destrutividade de pressionar End test, você precisa modificar algum recurso do seu aplicativo:
- Faça com que o botão pareça importante para chamar sua atenção
- prompt -se com uma mensagem de confirmação antes de terminar o teste para garantir que você não o termine prematuramente
Mostre e oculte seu modal de confirmação
Mude para o diretório present-confirmation-modal/ab-test
do repositório de cursos:
$cd nru-programmability-course/present-confirmation-modal/ab-test
Este diretório contém o código que seu aplicativo deve ter neste ponto do curso. Ao navegar para o diretório correto no início de cada lição, você deixa seu código personalizado para trás, protegendo-se assim de carregar código incorreto de uma lição para outra.
Em nerdlets/ab-test-nerdlet/end-test.js
, atualize Button
para usar o estilo DESTRUCTIVE
:
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> }}
Navegue até a raiz do seu Nerdpack em nru-programmability-course/present-confirmation-modal/ab-test
.
Gere um novo UUID para o seu Nerdpack:
$nr1 nerdpack:uuid -gf
Como você clonou o repositório de cursos que continha um Nerdpack existente, você precisa gerar seu próprio identificador exclusivo. Este UUID mapeia seu Nerdpack para sua conta New Relic.
Sirva seu aplicativo localmente:
$nr1 nerdpack:serve
Acesse https://one.newrelic.com?nerdpacks=local e visualize seu aplicativo em Apps > Your apps.
Agora você estilizou seu botão para transmitir suas consequências destrutivas, mas isso não é suficiente para evitar que você clique nele acidentalmente. Em seguida, você cria um escudo para backend do seu site. Essa camada extra de proteção exige que você confirme que pretende encerrar o teste antes de fazê-lo.
Adicione um Modal
a 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> }}
Seu novo modal contém um título, uma mensagem de confirmação, a versão vencedora do design e dois botões. Você explorará alguns desses componentes posteriormente neste curso.
Com seu Nerdpack servido localmente, visualize seu aplicativo para ver seu novo Modal
.
Dica
Lembre-se, enquanto seu servidor estiver em execução, ele será atualizado automaticamente quando você salvar seu código.
O modal parece ótimo, mas tem três problemas:
- Estava presente antes de você clicar em End test
- Você não pode descartá-lo
- Sempre diz que você selecionou "Versão A", mesmo que não tenha
Nas etapas a seguir, você corrigirá todos esses três problemas.
Em EndTestButton
, inicialize state
com um valor para 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> }}
modalHidden
determina se deve ou não ocultar o modal. O valor padrão de modalHidden
é true
porque você deseja mostrar o modal somente ao selecionar End test.
Forneça modalHidden
para 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> }}
Primeiro, você criou um construtor para aceitar adereços de componentes. Isso fornece ao seu componente acesso à propriedade modalHidden
que você passou em EndTestSection
. Em seguida, você fornece o valor de modalHidden
para a propriedade hidden
do componente Modal
.
Adicione e vincule dois novos métodos a 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> }}
Use closeModal
e showModal
para fechar e mostrar seu modal, respectivamente, dependendo de como o usuário interage com o modal.
Mostre o modal ao clicar emEnd 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> }}
Aqui, você forneceu showModal()
como retorno de chamada para o evento onClick
do componente Button
.
Volte para https://one.newrelic.com?nerdpacks=local e veja suas alterações.
O modal está oculto por padrão. Clique em End test para ver o modal.
Feche o modal do retorno de chamada onClose
do componente Modal
e dos botões Yes, end test e No, continue 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} 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> }}
Volte para https://one.newrelic.com?nerdpacks=local e veja suas alterações.
Clique em End test. O modal abre e exibe sua mensagem de confirmação. Feche o modal clicando no X no canto superior direito, em qualquer um de seus botões, ou mesmo no espaço escuro à sua esquerda.
Observe que o modal diz que você escolheu “Versão A”, mesmo que escolha “Versão B”. Isso ocorre porque a "Versão A" está codificada no texto Modal
. A seguir, você tornará isso dinâmico.
Use a versão que você selecionou em seu modal
Em EndTestSection
, passe selectedVersion
para 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> }}
Agora você pode acessar a versão selecionada nas propriedades do componente EndTestButton
.
Use selectedVersion
na sua mensagem de confirmação:
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> }}
Volte para https://one.newrelic.com?nerdpacks=local e veja suas alterações.
Selecione "Versão B" no menu. Clique em End test para ver a "Versão B" no modal de confirmação.
Quando terminar, pare de servir seu aplicativo New Relic pressionando CTRL+C
na janela do terminal do seu servidor local.
Parabéns! Você trabalhou muito e isso fica evidente na utilidade do seu aplicativo. Você criou gráficos que mostram dados simulados. Você organizou seus gráficos em uma estrutura legível. Você adicionou uma interface para seu usuário interagir com o teste. Agora, você precisa de alguns dados reais. Na próxima lição, você substituirá os dados simulados nos seus gráficos por dados reais do seu serviço backend.
Dica
Esta lição faz parte de um curso que ensina como construir um aplicativo New Relic do zero. Continue para a próxima lição: Adicione componentes NrqlQuery ao seu nerdlet.