Skip to content

Commit

Permalink
feat: add target audience filters to the publish modal(Issue #433) (#570
Browse files Browse the repository at this point in the history
)

Co-authored-by: Ilya Bondar <[email protected]>
  • Loading branch information
denys-kolomiitsev and IlyaBondar authored Jan 25, 2024
1 parent ba3892a commit a528357
Show file tree
Hide file tree
Showing 18 changed files with 1,010 additions and 41 deletions.
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ dist

.github
helm
__tests__
__tests__
2 changes: 1 addition & 1 deletion src/components/Chat/Addons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const Addon = ({
<ModelIcon entity={addonsMap[addonId]} entityId={addonId} size={15} />
<span>{addonsMap[addonId]?.name || addonId}</span>
{isSelected && !preselectedAddonsIds.includes(addonId) && (
<IconX height={12} width={12} className="text-secondary" />
<IconX size={14} className="text-secondary" />
)}
</button>
);
Expand Down
6 changes: 1 addition & 5 deletions src/components/Chat/AddonsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,7 @@ const SelectedAddon = ({
<ModelIcon entity={addon} entityId={addon.id} size={15} />
<span>{addon.name}</span>
{!isPreselected && (
<IconX
height={12}
width={12}
className="text-secondary hover:text-accent-primary"
/>
<IconX size={14} className="text-secondary hover:text-accent-primary" />
)}
</button>
);
Expand Down
72 changes: 72 additions & 0 deletions src/components/Chat/Publish/FilterTypeSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { IconChevronDown } from '@tabler/icons-react';
import { MouseEvent, useState } from 'react';

import { useTranslation } from 'next-i18next';

import classNames from 'classnames';

import { FiltersTypes } from '@/src/types/share';
import { Translation } from '@/src/types/translation';

import { Menu, MenuItem } from '../../Common/DropdownMenu';

interface FilterTypeProps {
id: string;
filterTypes: string[];
selectedType: string;
onChangeFilterType: (filterType: FiltersTypes) => void;
}

export function FilterTypeSelect({
id,
filterTypes,
selectedType,
onChangeFilterType,
}: FilterTypeProps) {
const [isOpen, setIsOpen] = useState(false);

const { t } = useTranslation(Translation.SideBar);

const onChangeHandler = (e: MouseEvent<HTMLButtonElement>) => {
onChangeFilterType(e.currentTarget.value as FiltersTypes);
setIsOpen(false);
};

return (
<div
data-qa={`filter-selector-${id}`}
className="h-[38px] w-full max-w-[140px] grow rounded border border-primary focus-within:border-accent-primary focus:border-accent-primary"
>
<Menu
className="w-full px-3"
onOpenChange={setIsOpen}
trigger={
<div className="flex items-center justify-between gap-2">
{selectedType}
<IconChevronDown
data-qa={`open-filter-dropdown-${id}`}
className={classNames(
'shrink-0 text-primary transition-all',
isOpen && 'rotate-180',
)}
width={18}
height={18}
/>
</div>
}
>
<div className="bg-layer-3">
{filterTypes.map((filterType) => (
<MenuItem
key={filterType}
className="max-w-[350px] hover:bg-accent-primary-alpha"
item={t(filterType)}
value={filterType}
onClick={onChangeHandler}
/>
))}
</div>
</Menu>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ import { Translation } from '@/src/types/translation';
import { stopBubbling } from '@/src/constants/chat';
import { PUBLISHING_FOLDER_NAME } from '@/src/constants/folders';

import SidebarActionButton from '../Buttons/SidebarActionButton';
import ContextMenu from '../Common/ContextMenu';
import Tooltip from '../Common/Tooltip';
import DownloadRenderer from '../Files/Download';
import SidebarActionButton from '../../Buttons/SidebarActionButton';
import ContextMenu from '../../Common/ContextMenu';
import Tooltip from '../../Common/Tooltip';
import DownloadRenderer from '../../Files/Download';

interface Props {
file: DialFile;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IconHelpCircle } from '@tabler/icons-react';
import {
ChangeEvent,
ClipboardEvent,
Expand All @@ -24,7 +25,11 @@ import { onBlur } from '@/src/utils/app/style-helpers';

import { ShareEntity } from '@/src/types/common';
import { DialFile } from '@/src/types/files';
import { SharingType } from '@/src/types/share';
import {
SharingType,
TargetAudienceFilter,
UserGroup,
} from '@/src/types/share';
import { Translation } from '@/src/types/translation';

import { useAppDispatch, useAppSelector } from '@/src/store/hooks';
Expand All @@ -33,11 +38,14 @@ import { PUBLISHING_FOLDER_NAME } from '@/src/constants/folders';

import { ChangePathDialog } from '@/src/components/Chat/ChangePathDialog';

import CollapsableSection from '../Common/CollapsableSection';
import EmptyRequiredInputMessage from '../Common/EmptyRequiredInputMessage';
import { ErrorMessage } from '../Common/ErrorMessage';
import Modal from '../Common/Modal';
import CollapsableSection from '../../Common/CollapsableSection';
import EmptyRequiredInputMessage from '../../Common/EmptyRequiredInputMessage';
import { ErrorMessage } from '../../Common/ErrorMessage';
import Modal from '../../Common/Modal';
import Tooltip from '../../Common/Tooltip';
import { PublishAttachment } from './PublishAttachment';
import { TargetAudienceFilterComponent } from './TargetAudienceFilter';
import { UserGroupFilter } from './UserGroupFilter';

import { v4 as uuidv4 } from 'uuid';

Expand All @@ -59,7 +67,7 @@ const getPrefix = (item: ShareEntity): string => {
}
};

export default function PublishModal({
export default function PublishWizard({
entity,
isOpen,
onClose,
Expand All @@ -81,14 +89,17 @@ export default function PublishModal({
const [isChangeFolderModalOpened, setIsChangeFolderModalOpened] =
useState(false);
const [version, setVersion] = useState<string>('');

const isVersionUnique = useAppSelector((state) =>
isPublishVersionUnique(type)(state, entity.id, version.trim()),
);

const files = useAppSelector((state) =>
getAttachments(type)(state, entity.id),
);
const [userGroups, setUserGroups] = useState<UserGroup[]>([]);
const [otherTargetAudienceFilters, setOtherTargetAudienceFilters] = useState<
TargetAudienceFilter[]
>([]);

const nameOnChangeHandler = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -141,6 +152,15 @@ export default function PublishModal({
setIsChangeFolderModalOpened(true);
}, []);

const handleOnChangeFilters = (targetFilter: TargetAudienceFilter) => {
setOtherTargetAudienceFilters((prev) => {
const filters = prev
.filter(({ id }) => id !== targetFilter.id)
.concat(targetFilter);
return filters;
});
};

const handlePublish = useCallback(
(e: MouseEvent<HTMLButtonElement> | ClipboardEvent<HTMLInputElement>) => {
e.preventDefault();
Expand Down Expand Up @@ -168,6 +188,10 @@ export default function PublishModal({
fileNameMapping: new Map( // invert mapping
Array.from(newFileNames.current, (entry) => [entry[1], entry[0]]),
),
targetAudienceFilters: {
userGroups,
other: otherTargetAudienceFilters,
},
}),
);
onClose();
Expand All @@ -181,6 +205,8 @@ export default function PublishModal({
path,
publishAction,
version,
userGroups,
otherTargetAudienceFilters,
],
);

Expand All @@ -196,7 +222,7 @@ export default function PublishModal({
<Modal
portalId="theme-main"
containerClassName={classNames(
'group/modal inline-block h-[747px] min-w-full max-w-[1100px] !bg-layer-2 md:min-w-[550px]',
'group/modal inline-block h-[747px] min-w-full max-w-[1100px] !bg-layer-2 md:min-w-[550px] lg:min-w-[1000px] xl:w-[1100px]',
{ 'w-full': files.length },
)}
dataQa="publish-modal"
Expand Down Expand Up @@ -297,26 +323,65 @@ export default function PublishModal({
</section>

<section className="flex flex-col px-5 py-4">
<h2>{t('Target Audience Filters')}</h2>
<h2 className="flex flex-row gap-2">
{t('Target Audience Filters')}

<Tooltip
placement="top"
tooltip={
<div className="max-w-[230px] break-words text-xs">
{t(
'The collection will be published for all users who meet AT LEAST ONE option from every',
)}
</div>
}
>
<IconHelpCircle
size={18}
className="text-secondary hover:text-accent-primary"
/>
</Tooltip>
</h2>

<CollapsableSection
name={t('User Group')}
dataQa="filter-user-group"
openByDefault={false}
className="!pl-0"
>
<UserGroupFilter
onChangeUserGroups={setUserGroups}
initialSelectedUserGroups={userGroups}
/>
</CollapsableSection>

{[
'UserGroup',
'JobTitle',
'AssignedProjects',
'UserGroup',
'JobTitle',
'AssignedProjects',
].map((v, idx) => (
<CollapsableSection
name={v}
dataQa={`filter-${v}`}
key={`filter-${v}-${idx}`}
openByDefault={false}
className="!pl-0"
>
TBD
</CollapsableSection>
))}
{ id: 'JobTitle', name: 'Job Title' },
{ id: 'AssignedProjects', name: 'Assigned Projects' },
{ id: 'filter4', name: 'Filter 4' },
{ id: 'filter5', name: 'Filter 5' },
{ id: 'filter6', name: 'Filter 6' },
].map((v, idx) => {
const initialSelectedFilter = otherTargetAudienceFilters.find(
({ id }) => id === v.id,
);
return (
<CollapsableSection
name={v.name}
dataQa={`filter-${v.id}`}
key={`filter-${v.id}-${idx}`}
openByDefault={false}
className="!pl-0"
>
<TargetAudienceFilterComponent
name={v.name}
id={v.id}
initialSelectedFilter={initialSelectedFilter}
onChangeFilter={handleOnChangeFilters}
/>
</CollapsableSection>
);
})}
</section>
</div>
{(type === SharingType.Conversation ||
Expand Down
30 changes: 30 additions & 0 deletions src/components/Chat/Publish/RegexParamInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ChangeEvent, useCallback } from 'react';

interface RegexParamInputProps {
regEx: string;
onRegExChange: (regExp: string) => void;
}

export function RegexParamInput({
regEx,
onRegExChange,
}: RegexParamInputProps) {
const handleRegExChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
onRegExChange(e.target.value);
},
[onRegExChange],
);

return (
<div className="flex w-full flex-wrap rounded border border-primary p-1 focus-within:border-accent-primary">
<input
className="w-full bg-transparent py-1 pl-2 outline-none placeholder:text-secondary"
type="text"
placeholder={'Enter regular expression...'}
value={regEx}
onChange={handleRegExChange}
/>
</div>
);
}
Loading

0 comments on commit a528357

Please sign in to comment.