Skip to content

Commit

Permalink
Fix: Enable screen reader confirmation feedback (#802)
Browse files Browse the repository at this point in the history
* add announced component

* localize announced messages

* add announced component

* update aria-label and add announced component

* localize screen reader messages

* replace variable name

* replace local state

* replace class component

* remove unused declarations

* fix linting error

* refactor code

* remove inline styles
  • Loading branch information
ElinorW committed Jan 20, 2021
1 parent dc7e1fd commit 5bf4550
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 111 deletions.
10 changes: 5 additions & 5 deletions src/app/views/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
Announced,
IStackTokens, ITheme, styled
} from 'office-ui-fabric-react';
import React, { Component } from 'react';
Expand All @@ -24,6 +25,7 @@ import { logIn } from '../services/graph-client/msal-service';
import { GRAPH_URL } from '../services/graph-constants';
import { parseSampleUrl } from '../utils/sample-url-generation';
import { substituteTokens } from '../utils/token-helpers';
import { translateMessage } from '../utils/translate-messages';
import { appTitleDisplayOnFullScreen, appTitleDisplayOnMobileScreen } from './app-sections/AppTitle';
import { headerMessaging } from './app-sections/HeaderMessaging';
import { statusMessages } from './app-sections/StatusMessages';
Expand Down Expand Up @@ -77,7 +79,7 @@ class App extends Component<IAppProps, IAppState> {
this.state = {
selectedVerb: 'GET',
mobileScreen: false,
hideDialog: true,
hideDialog: true
};
}

Expand Down Expand Up @@ -287,7 +289,6 @@ class App extends Component<IAppProps, IAppState> {
</div>;
}


public render() {
const classes = classNames(this.props);
const { authenticated, graphExplorerMode, queryState, minimised, termsOfUse, sampleQuery,
Expand Down Expand Up @@ -326,13 +327,12 @@ class App extends Component<IAppProps, IAppState> {
sidebarWidth = layout = 'col-xs-12 col-sm-12';
}




return (
// @ts-ignore
<ThemeContext.Provider value={this.props.appTheme}>
<div className={`container-fluid ${classes.app}`}>
<Announced message={!showSidebar ?
translateMessage('Sidebar minimized') : translateMessage('Sidebar maximized')} />
<div className='row'>
{graphExplorerMode === Mode.Complete && (
<div className={sidebarWidth}>
Expand Down
9 changes: 5 additions & 4 deletions src/app/views/query-response/QueryResponse.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
Announced,
DefaultButton,
FontSizes,
getId,
Expand Down Expand Up @@ -32,7 +33,7 @@ import './query-response.scss';
class QueryResponse extends Component<
IQueryResponseProps,
IQueryResponseState
> {
> {
constructor(props: any) {
super(props);
this.state = {
Expand Down Expand Up @@ -159,7 +160,7 @@ class QueryResponse extends Component<
/>
</Pivot>
</div>

<Announced message={this.state.showModal ? translateMessage('Response area expanded') : ''} />
{
// @ts-ignore
<Modal
Expand All @@ -175,9 +176,9 @@ class QueryResponse extends Component<
},
}}
iconProps={{ iconName: 'Cancel' }}
ariaLabel='Close popup modal'
ariaLabel={translateMessage('Close expanded response area')}
onClick={this.toggleExpandResponse}
/>;
/>
<Pivot className='pivot-response' onLinkClick={(pivotItem) => onPivotItemClick(sampleQuery, pivotItem)}>
{pivotItems}
</Pivot>
Expand Down
6 changes: 3 additions & 3 deletions src/app/views/query-runner/query-input/QueryInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export class QueryInput extends Component<IQueryInputProps, any> {
const {
intl: { messages },
}: any = this.props;
const showError = !authenticated && sampleQuery.selectedVerb != 'GET';
const showError = !authenticated && sampleQuery.selectedVerb !== 'GET';
const verbSelector: any = queryRunnerStyles().verbSelector;
verbSelector.title = {
...verbSelector.title,
Expand All @@ -96,7 +96,7 @@ export class QueryInput extends Component<IQueryInputProps, any> {
selectedKey={sampleQuery.selectedVerb}
options={httpMethods}
styles={verbSelector}
errorMessage={showError ? translateMessage('Sign in to use this method') : undefined }
errorMessage={showError ? translateMessage('Sign in to use this method') : undefined}
onChange={(event, method) => handleOnMethodChange(method)}
/>
</div>
Expand All @@ -119,7 +119,7 @@ export class QueryInput extends Component<IQueryInputProps, any> {
<SubmitButton
className='run-query-button'
text={messages['Run Query']}
disabled={showError}
disabled={showError}
role='button'
handleOnClick={() => handleOnRunQuery()}
submitting={submitting}
Expand Down
172 changes: 74 additions & 98 deletions src/app/views/query-runner/request/headers/RequestHeaders.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,57 @@
import { PrimaryButton, TextField } from 'office-ui-fabric-react';
import React, { Component } from 'react';
import { Announced, PrimaryButton, styled, TextField } from 'office-ui-fabric-react';
import React, { useState } from 'react';
import { FormattedMessage, injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';
import { useDispatch, useSelector } from 'react-redux';

import { IRequestHeadersProps } from '../../../../../types/request';
import * as queryInputActionCreators from '../../../../services/actions/query-input-action-creators';
import { translateMessage } from '../../../../utils/translate-messages';
import { classNames } from '../../../classnames';
import { headerStyles } from './Headers.styles';
import HeadersList from './HeadersList';

class RequestHeaders extends Component<IRequestHeadersProps, any> {
constructor(props: any) {
super(props);
this.state = {
headerName: '',
headerValue: '',
};
}
interface IHeader {
name: string;
value: string;
}

const RequestHeaders = (props: any) => {
const sampleQuery = useSelector((state: any) => state.sampleQuery);
const [headerName, setHeaderName] = useState('');
const [headerValue, setHeaderValue] = useState('');
const [announcedMessage, setAnnouncedMessage] = useState('');

const { intl: { messages } } = props;
const sampleQueryHeaders = sampleQuery.sampleHeaders;

private handleOnHeaderNameChange = (name?: string) => {
const dispatch = useDispatch();
const classes = classNames(props);

const handleOnHeaderNameChange = (name?: string) => {
if (name) {
this.setState({
headerName: name,
});
setHeaderName(name);
}
};

private handleOnHeaderValueChange = (value?: string) => {
const handleOnHeaderValueChange = (value?: string) => {
if (value) {
this.setState({ headerValue: value });
setHeaderValue(value);
}
};

private handleOnHeaderDelete = (header: any) => {
const { actions, sampleQuery } = this.props;
const handleOnHeaderDelete = (header: IHeader) => {
let headers = [...sampleQuery.sampleHeaders];
headers = headers.filter(head => head.name !== header.name);

const query = sampleQuery;
const query = { ...sampleQuery };
query.sampleHeaders = headers;

if (actions) {
actions.setSampleQuery(query);
}

this.setState(this.state);
dispatch(queryInputActionCreators.setSampleQuery(query));
setAnnouncedMessage(translateMessage('Request Header deleted'));
};

private handleOnHeaderAdd = () => {
if (this.state.headerName !== '') {
const { headerName, headerValue } = this.state;
const { actions } = this.props;
let { sampleHeaders } = this.props.sampleQuery;
const handleOnHeaderAdd = () => {
if (headerName) {
let { sampleHeaders } = sampleQuery;
const header = { name: headerName, value: headerValue };

if (!sampleHeaders) {
Expand All @@ -63,76 +63,52 @@ class RequestHeaders extends Component<IRequestHeadersProps, any> {

const newHeaders = [header, ...sampleHeaders];

this.setState({
headerName: '',
headerValue: '',
});
setHeaderName('');
setHeaderValue('');
setAnnouncedMessage(translateMessage('Request Header added'));

if (actions) {
const query = this.props.sampleQuery;
query.sampleHeaders = newHeaders;
actions.setSampleQuery(query);
}
const query = { ...sampleQuery };
query.sampleHeaders = newHeaders;
dispatch(queryInputActionCreators.setSampleQuery(query));
}
};

public render() {
// @ts-ignore
const { sampleQuery, intl: { messages } } = this.props;
const headers = sampleQuery.sampleHeaders;
const container: any = headerStyles().container;

return (
<div style={container}>
<div className='row'>
<div className='col-sm-5'>
<TextField className='header-input'
placeholder={messages.Key}
value={this.state.headerName}
onChange={(event, name) => this.handleOnHeaderNameChange(name)}
/>
</div>
<div className='col-sm-5'>
<TextField
className='header-input'
placeholder={messages.Value}
value={this.state.headerValue}
onChange={(event, value) => this.handleOnHeaderValueChange(value)}
/>
</div>
<div className='col-sm-2 col-md-2'>
<PrimaryButton
style={{ width: '100%' }}
onClick={() => this.handleOnHeaderAdd()}>
<FormattedMessage id='Add' />
</PrimaryButton>
</div>
return (
<div className={classes.container}>
<Announced message={announcedMessage} />
<div className='row'>
<div className='col-sm-5'>
<TextField className='header-input'
placeholder={messages.Key}
value={headerName}
onChange={(event, name) => handleOnHeaderNameChange(name)}
/>
</div>
<div className='col-sm-5'>
<TextField
className='header-input'
placeholder={messages.Value}
value={headerValue}
onChange={(event, value) => handleOnHeaderValueChange(value)}
/>
</div>
<div className='col-sm-2 col-md-2'>
<PrimaryButton
style={{ width: '100%' }}
onClick={handleOnHeaderAdd}>
<FormattedMessage id='Add' />
</PrimaryButton>
</div>
<hr />
<HeadersList
messages={messages}
handleOnHeaderDelete={(event: any, header: any) => this.handleOnHeaderDelete(header)}
headers={headers}
/>
</div>
);
}
}

function mapDispatchToProps(dispatch: Dispatch): object {
return {
actions: bindActionCreators(
{ ...queryInputActionCreators },
dispatch),
};
}

function mapStateToProps(state: any) {
return {
sampleQuery: state.sampleQuery,
};
}

<hr />
<HeadersList
messages={messages}
handleOnHeaderDelete={(event: any, header: IHeader) => handleOnHeaderDelete(header)}
headers={sampleQueryHeaders}
/>
</div>
);
};
// @ts-ignore
const WithIntl = injectIntl(RequestHeaders);
export default connect(mapStateToProps, mapDispatchToProps)(WithIntl);
const styledRequestHeaders = styled(injectIntl(RequestHeaders), headerStyles);
export default styledRequestHeaders;
10 changes: 9 additions & 1 deletion src/messages/GE.json
Original file line number Diff line number Diff line change
Expand Up @@ -328,5 +328,13 @@
"Query Sample Input": "Query sample input",
"popup blocked, allow pop-up windows in your browser": "popup blocked, allow pop-up windows in your browser",
"sign in to consent to permissions": "One of the following permissions is required to run the query. Sign in with an account that can consent to the permission you will choose.",
"Sign in to use this method": "Sign in to use this method"
"Sign in to use this method": "Sign in to use this method",
"Request Header deleted": "Request Header deleted",
"Request Header added": "Request Header added",
"Sidebar minimized": "Sidebar minimized",
"Sidebar maximized": "Sidebar maximized",
"Response area expanded": "Response area expanded",
"Close expanded response area": "Close expanded response area"

}

0 comments on commit 5bf4550

Please sign in to comment.