Skip to content

Commit

Permalink
organize code and fix a11y
Browse files Browse the repository at this point in the history
  • Loading branch information
cansuaa committed Jan 28, 2025
1 parent 453762a commit b9fa6fb
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 89 deletions.
116 changes: 108 additions & 8 deletions pages/bluedialog/bluedialog.page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,118 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
import React, { useRef } from 'react';

import { Box } from '~components';
import { Box, Button, Checkbox, Form, FormField, SpaceBetween, Textarea } from '~components';

import Bluedialog from './dialog';
import FeedbackDialog from './dialog';

export default function BluedialogPage() {
import styles from './styles.scss';

export default function GenAIFeedback() {
const [showDialog, setShowDialog] = React.useState(true);
const submitData = (data: any) => {
console.log(data); // submit the form with these values to determine next action
const [showFeedbackSubmission, setShowFeedbackSubmission] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState<string | null>();
const [feedbackOptions, setFeedbackOptions] = React.useState({
harmful: false,
incomplete: false,
inaccurate: false,
other: false,
});
const [feedbackText, setFeedbackText] = React.useState('');
const checkboxRef = useRef<HTMLElement>(null);

const selectOption = (option: string, checked: boolean) => {
setFeedbackOptions({ ...feedbackOptions, [option]: checked });
setErrorMessage(null);
};

const submitData = () => {
// Validation
const isFeedbackOptionSelected = Object.values(feedbackOptions).some(val => !!val);
if (!isFeedbackOptionSelected) {
setErrorMessage('At least one option must be selected.');
// Move focus to the required input
if (checkboxRef.current) {
checkboxRef.current.focus();
}
return;
}

// Submission
setShowDialog(false);
setShowFeedbackSubmission(true);
};
const skipDialog = () => {

const dismissDialog = () => {
setShowDialog(false);
};
return <Box padding="xxl">{showDialog && <Bluedialog onSubmit={submitData} onSkip={skipDialog} />}</Box>;

return (
<Box padding="xxl">
{showDialog && (
<FeedbackDialog
onDismiss={dismissDialog}
footer={
<div className={styles['footer-buttons']}>
<Button onClick={submitData} ariaLabel="Submit form">
Submit
</Button>
</div>
}
>
<Form>
<SpaceBetween direction="vertical" size="l">
<FormField label="What did you dislike about the response?" errorText={errorMessage}>
<SpaceBetween size="xxl" direction="horizontal">
<Checkbox
ref={checkboxRef}
checked={feedbackOptions.harmful}
onChange={({ detail }) => selectOption('harmful', detail.checked)}
>
Harmful
</Checkbox>
<Checkbox
checked={feedbackOptions.incomplete}
onChange={({ detail }) => selectOption('incomplete', detail.checked)}
>
Incomplete
</Checkbox>
<Checkbox
checked={feedbackOptions.inaccurate}
onChange={({ detail }) => selectOption('inaccurate', detail.checked)}
>
Inaccurate
</Checkbox>
<Checkbox
checked={feedbackOptions.other}
onChange={({ detail }) => selectOption('other', detail.checked)}
>
Other
</Checkbox>
</SpaceBetween>
</FormField>

<FormField
label={
<span>
Tell us more - <i>optional</i>
</span>
}
stretch={true}
>
<Textarea
rows={1}
onChange={({ detail }) => setFeedbackText(detail.value)}
value={feedbackText}
placeholder={'Additional feedback'}
/>
</FormField>
</SpaceBetween>
</Form>
</FeedbackDialog>
)}

{showFeedbackSubmission && <Box color="text-body-secondary">Thank you for the additional feedback.</Box>}
</Box>
);
}
92 changes: 22 additions & 70 deletions pages/bluedialog/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
// SPDX-License-Identifier: Apache-2.0
import React, { useEffect, useRef } from 'react';

import { Box, Button, Checkbox, Form, FormField, SpaceBetween, Textarea } from '~components';
import { Button } from '~components';

import styles from './styles.scss';

export default function Bluedialog({ onSubmit, onSkip }: any) {
export default function FeedbackDialog({
children,
footer,
onDismiss,
}: {
children: React.ReactNode;
footer: React.ReactNode;
onDismiss: () => void;
}) {
const dialogRef = useRef<HTMLDivElement>(null);
const triggerRef = useRef<HTMLElement | null>(null);
// Inputs (these following can be clubbed into one state object)
const [feedbackOptions, setFeedbackOptions] = React.useState({
harmful: false,
incomplete: false,
inaccurate: false,
other: false,
});
const [feedbackText, setFeedbackText] = React.useState('');

useEffect(() => {
// Store the element that had focus before dialog opened
Expand All @@ -34,72 +34,24 @@ export default function Bluedialog({ onSubmit, onSkip }: any) {
};
}, []);

function submitData() {
onSubmit({ feedbackOptions, feedbackText });
}
function skipDialog() {
onSkip(); // can be used by the parent component to dismiss/ hide this dialog box
}

return (
<div
className={styles['blue-dialog-box']}
role={'dialog'}
aria-labelledby="feedback dialog"
ref={dialogRef}
className={styles['feedback-dialog']}
role="dialog"
aria-label="Feedback dialog"
aria-modal="false" // Maintains natural focus flow since it's an inline dialog
tabIndex={-1} // This allows the dialog to receive focus
>
<Form>
<Box padding={'l'}>
<div className={styles['blue-dialog-box__close']}>
<Button iconName="close" variant="icon" onClick={skipDialog} aria-label="Close dialog" />
</div>
<SpaceBetween direction="vertical" size="l">
<FormField label="What did you dislike about the response?">
<SpaceBetween size={'xxl'} direction={'horizontal'}>
<Checkbox
checked={feedbackOptions.harmful}
onChange={({ detail }) => setFeedbackOptions({ ...feedbackOptions, harmful: detail.checked })}
>
Harmful
</Checkbox>
<Checkbox
checked={feedbackOptions.incomplete}
onChange={({ detail }) => setFeedbackOptions({ ...feedbackOptions, incomplete: detail.checked })}
>
Incomplete
</Checkbox>
<Checkbox
checked={feedbackOptions.inaccurate}
onChange={({ detail }) => setFeedbackOptions({ ...feedbackOptions, inaccurate: detail.checked })}
>
Inaccurate
</Checkbox>
<Checkbox
checked={feedbackOptions.other}
onChange={({ detail }) => setFeedbackOptions({ ...feedbackOptions, other: detail.checked })}
>
Other
</Checkbox>
</SpaceBetween>
</FormField>
<FormField label="Tell us more - optional" stretch={true}>
<Textarea
rows={1}
onChange={({ detail }) => setFeedbackText(detail.value)}
value={feedbackText}
placeholder={'Additional feedback'}
/>
</FormField>
</SpaceBetween>
</Box>

<div className={styles['blue-dialog-box__footer']}>
<Button onClick={submitData} ariaLabel="Submit form">
Submit
</Button>
<div className={styles.content}>
<div className={styles.dismiss}>
<Button iconName="close" variant="icon" onClick={onDismiss} ariaLabel="Close dialog" />
</div>
</Form>

<div className={styles['inner-content']}>{children}</div>
</div>

<div className={styles.footer}>{footer}</div>
</div>
);
}
41 changes: 30 additions & 11 deletions pages/bluedialog/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,44 @@
*/
@use '~design-tokens' as awsui;

.blue-dialog-box {
.feedback-dialog {
// these to be feedback dialog's own design tokens
border-block: 1px solid awsui.$color-border-status-info;
border-inline: 1px solid awsui.$color-border-status-info;
background-color: awsui.$color-background-status-info;
border-start-start-radius: 16px;
border-start-end-radius: 16px;
border-end-start-radius: 16px;
border-end-end-radius: 16px;

border-start-start-radius: awsui.$border-radius-container;
border-start-end-radius: awsui.$border-radius-container;
border-end-start-radius: awsui.$border-radius-container;
border-end-end-radius: awsui.$border-radius-container;

outline-offset: 5px;
}

.content {
display: flex;
align-items: baseline;

padding-block-start: awsui.$space-scaled-s;
padding-block-end: awsui.$space-scaled-l;
padding-inline: awsui.$space-container-horizontal;
}

.dismiss {
order: 1;
}

.blue-dialog-box__close {
float: right;
.inner-content {
flex: 1;
}

.blue-dialog-box__footer {
.footer {
border-block-start: 1px solid awsui.$color-border-divider-default;
padding-block: 10px;
padding-inline: 20px;
padding-block: awsui.$space-scaled-s;
padding-inline: awsui.$space-container-horizontal;
}

.footer-buttons {
display: flex;
flex-direction: row-reverse;
gap: 20px;
}

0 comments on commit b9fa6fb

Please sign in to comment.