[questions][ui] add to list dropdown

pull/468/head
wlren 3 years ago
parent 9f214cddc2
commit a08d7e22b7

@ -0,0 +1,89 @@
import { forwardRef, Fragment, useEffect, useRef, useState } from 'react';
import { Menu, Transition } from '@headlessui/react';
import { CheckIcon, HeartIcon } from '@heroicons/react/20/solid';
import { lists } from '~/pages/questions/lists';
function classNames(...classes: Array<string>) {
return classes.filter(Boolean).join(' ');
}
export default function AddToListDropdown() {
const [menuOpened, setMenuOpened] = useState(false);
const ref = useRef() as React.MutableRefObject<HTMLDivElement>;
const addClickOutsideListener = () => {
document.addEventListener('click', handleClickOutside, true);
};
const handleClickOutside = (event: MouseEvent) => {
if (!ref.current.contains(event.target as Node)) {
setMenuOpened(false);
document.removeEventListener('click', handleClickOutside, true);
}
};
const CustomMenuButton = ({ children }: any) => (
<button
className="focus:ring-primary-500 inline-flex w-full justify-center rounded-md border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-slate-100"
type="button"
onClick={() => {
addClickOutsideListener();
setMenuOpened(!menuOpened);
}}>
{children}
</button>
);
return (
<Menu ref={ref} as="div" className="relative inline-block text-left">
<div>
<Menu.Button as={CustomMenuButton}>
<HeartIcon aria-hidden="true" className="-ml-1 mr-2 h-5 w-5" />
Add to List
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
show={menuOpened}>
<Menu.Items
className="absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-slate-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
static={true}>
{menuOpened && (
<>
{lists.map((list) => (
<div key={list.id} className="py-1">
<Menu.Item>
{({ active }) => (
<button
className={classNames(
active
? 'bg-slate-100 text-slate-900'
: 'text-slate-700',
'group flex w-full items-center px-4 py-2 text-sm',
)}
type="button">
<CheckIcon
aria-hidden="true"
className="mr-3 h-5 w-5 text-slate-400 group-hover:text-slate-500"
/>
list.name
</button>
)}
</Menu.Item>
</div>
))}
</>
)}
</Menu.Items>
</Transition>
</Menu>
);
}

@ -11,6 +11,7 @@ import { Button } from '@tih/ui';
import { useQuestionVote } from '~/utils/questions/useVote'; import { useQuestionVote } from '~/utils/questions/useVote';
import AddToListDropdown from '../../AddToListDropdown';
import type { CreateQuestionEncounterData } from '../../forms/CreateQuestionEncounterForm'; import type { CreateQuestionEncounterData } from '../../forms/CreateQuestionEncounterForm';
import CreateQuestionEncounterForm from '../../forms/CreateQuestionEncounterForm'; import CreateQuestionEncounterForm from '../../forms/CreateQuestionEncounterForm';
import QuestionAggregateBadge from '../../QuestionAggregateBadge'; import QuestionAggregateBadge from '../../QuestionAggregateBadge';
@ -79,7 +80,16 @@ type CreateEncounterProps =
showCreateEncounterButton?: false; showCreateEncounterButton?: false;
}; };
type AddToListProps =
| {
showAddToList: true;
}
| {
showAddToList?: false;
};
export type BaseQuestionCardProps = ActionButtonProps & export type BaseQuestionCardProps = ActionButtonProps &
AddToListProps &
AnswerStatisticsProps & AnswerStatisticsProps &
CreateEncounterProps & CreateEncounterProps &
DeleteProps & DeleteProps &
@ -117,6 +127,7 @@ export default function BaseQuestionCard({
showHover, showHover,
onReceivedSubmit, onReceivedSubmit,
showDeleteButton, showDeleteButton,
showAddToList,
onDelete, onDelete,
truncateContent = true, truncateContent = true,
}: BaseQuestionCardProps) { }: BaseQuestionCardProps) {
@ -135,12 +146,17 @@ export default function BaseQuestionCard({
)} )}
<div className="flex flex-col items-start gap-2"> <div className="flex flex-col items-start gap-2">
<div className="flex items-baseline justify-between"> <div className="flex items-baseline justify-between">
<div className="flex items-baseline gap-2 text-slate-500"> <div className="flex items-center gap-2 text-slate-500">
<QuestionTypeBadge type={type} /> <QuestionTypeBadge type={type} />
<QuestionAggregateBadge statistics={companies} variant="primary" /> <QuestionAggregateBadge statistics={companies} variant="primary" />
<QuestionAggregateBadge statistics={locations} variant="success" /> <QuestionAggregateBadge statistics={locations} variant="success" />
<QuestionAggregateBadge statistics={roles} variant="danger" /> <QuestionAggregateBadge statistics={roles} variant="danger" />
<p className="text-xs">{timestamp}</p> <p className="text-xs">{timestamp}</p>
{showAddToList && (
<div className="pl-4">
<AddToListDropdown></AddToListDropdown>
</div>
)}
</div> </div>
{showActionButton && ( {showActionButton && (
<Button <Button

@ -4,6 +4,7 @@ import BaseQuestionCard from './BaseQuestionCard';
export type QuestionOverviewCardProps = Omit< export type QuestionOverviewCardProps = Omit<
BaseQuestionCardProps & { BaseQuestionCardProps & {
showActionButton: false; showActionButton: false;
showAddToList: true;
showAnswerStatistics: false; showAnswerStatistics: false;
showCreateEncounterButton: true; showCreateEncounterButton: true;
showDeleteButton: false; showDeleteButton: false;
@ -13,6 +14,7 @@ export type QuestionOverviewCardProps = Omit<
| 'actionButtonLabel' | 'actionButtonLabel'
| 'onActionButtonClick' | 'onActionButtonClick'
| 'showActionButton' | 'showActionButton'
| 'showAddToList'
| 'showAnswerStatistics' | 'showAnswerStatistics'
| 'showCreateEncounterButton' | 'showCreateEncounterButton'
| 'showDeleteButton' | 'showDeleteButton'
@ -25,6 +27,7 @@ export default function FullQuestionCard(props: QuestionOverviewCardProps) {
<BaseQuestionCard <BaseQuestionCard
{...props} {...props}
showActionButton={false} showActionButton={false}
showAddToList={true}
showAnswerStatistics={false} showAnswerStatistics={false}
showCreateEncounterButton={true} showCreateEncounterButton={true}
showReceivedStatistics={false} showReceivedStatistics={false}

@ -16,8 +16,7 @@ import { APP_TITLE } from '~/utils/questions/constants';
import { SAMPLE_QUESTION } from '~/utils/questions/constants'; import { SAMPLE_QUESTION } from '~/utils/questions/constants';
import createSlug from '~/utils/questions/createSlug'; import createSlug from '~/utils/questions/createSlug';
export default function ListPage() { export const questions = [
const questions = [
SAMPLE_QUESTION, SAMPLE_QUESTION,
SAMPLE_QUESTION, SAMPLE_QUESTION,
SAMPLE_QUESTION, SAMPLE_QUESTION,
@ -33,16 +32,17 @@ export default function ListPage() {
SAMPLE_QUESTION, SAMPLE_QUESTION,
SAMPLE_QUESTION, SAMPLE_QUESTION,
SAMPLE_QUESTION, SAMPLE_QUESTION,
]; ];
const lists = [ export const lists = [
{ id: 1, name: 'list 1', questions }, { id: 1, name: 'list 1', questions },
{ id: 2, name: 'list 2', questions }, { id: 2, name: 'list 2', questions },
{ id: 3, name: 'list 3', questions }, { id: 3, name: 'list 3', questions },
{ id: 4, name: 'list 4', questions }, { id: 4, name: 'list 4', questions },
{ id: 5, name: 'list 5', questions }, { id: 5, name: 'list 5', questions },
]; ];
export default function ListPage() {
const [selectedList, setSelectedList] = useState( const [selectedList, setSelectedList] = useState(
(lists ?? []).length > 0 ? lists[0].id : '', (lists ?? []).length > 0 ? lists[0].id : '',
); );

Loading…
Cancel
Save