Skip to content

Commit

Permalink
feat(GoalParentDropdown): create component
Browse files Browse the repository at this point in the history
  • Loading branch information
DenisVorop committed Feb 27, 2024
1 parent ec2b249 commit 73794f9
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Suggestions": "",
"Create project": ""
}
17 changes: 17 additions & 0 deletions src/components/GoalParentDropdown/GoalParentDropdown.i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* eslint-disable */
// Do not edit, use generator to update
import { i18n, fmt, I18nLangSet } from 'easy-typed-intl';
import getLang from '../../../utils/getLang';

import ru from './ru.json';
import en from './en.json';

export type I18nKey = keyof typeof ru & keyof typeof en;
type I18nLang = 'ru' | 'en';

const keyset: I18nLangSet<I18nKey> = {};

keyset['ru'] = ru;
keyset['en'] = en;

export const tr = i18n<I18nLang, I18nKey>(keyset, fmt, getLang);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Suggestions": "Предложения",
"Create project": "Новый проект"
}
28 changes: 28 additions & 0 deletions src/components/GoalParentDropdown/GoalParentDropdown.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.DropdownTrigger {
min-width: 180px;
}

.DropdownPanelItem {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--gap-s);
width: 100%;
}

.DropdownPanelItem_id {
color: var(--text-secondary);
}

.DropdownTriggerValue {
display: inline-block;
white-space: nowrap;
width: 130px;
text-overflow: ellipsis;
overflow: hidden;
}

.CreateProjectButton {
margin-bottom: var(--gap-xs);
color: var(--text-secondary);
}
105 changes: 105 additions & 0 deletions src/components/GoalParentDropdown/GoalParentDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { Text, Button } from '@taskany/bricks/harmony';
import { useState, useEffect, useMemo, ComponentProps, useCallback } from 'react';
import { nullable } from '@taskany/bricks';
import { IconAddOutline } from '@taskany/icons';

import { useLocalStorage } from '../../hooks/useLocalStorage';
import { trpc } from '../../utils/trpcClient';
import { Dropdown, DropdownTrigger, DropdownPanel } from '../Dropdown/Dropdown';
import { ModalEvent, dispatchModalEvent } from '../../utils/dispatchModal';

import s from './GoalParentDropdown.module.css';
import { tr } from './GoalParentDropdown.i18n';

interface GoalParentDropdownProps {
error?: ComponentProps<typeof DropdownTrigger>['error'];
label?: ComponentProps<typeof DropdownTrigger>['label'];
value?: { id: string; title: string };
query?: string;
placeholder?: string;
disabled?: boolean;
onChange?: (project: { id: string; title: string }) => void;
}

export const GoalParentDropdown = ({
label,
query = '',
value,
placeholder,
disabled,
onChange,
...props
}: GoalParentDropdownProps) => {
const [inputState, setInputState] = useState(query);
const [recentProjectsCache] = useLocalStorage('recentProjectsCache', {});

useEffect(() => {
setInputState(query);
}, [query]);

const { data } = trpc.project.suggestions.useQuery(
{
query: inputState,
},
{
enabled: inputState.length >= 2,
cacheTime: 0,
staleTime: 0,
},
);

const recentProjects = Object.values(recentProjectsCache)
.sort((a, b) => b.rate - a.rate)
.slice(0, 10) // top 10
.map((p) => p.cache);

const items = useMemo<typeof recentProjects | typeof data>(
() => (data && data?.length > 0 ? data : recentProjects),
[data, recentProjects],
);

const handleCreateProject = useCallback(() => {
dispatchModalEvent(ModalEvent.GoalCreateModal)();
dispatchModalEvent(ModalEvent.ProjectCreateModal)();
}, []);

return (
<Dropdown>
<DropdownTrigger label={label} className={s.DropdownTrigger} {...props} readOnly={disabled}>
{nullable(value, ({ title }) => (
<Text size="s" as="span" className={s.DropdownTriggerValue} title={title}>
{title}
</Text>
))}
</DropdownTrigger>
<DropdownPanel
width={320}
value={value}
title={tr('Suggestions')}
items={items}
placeholder={placeholder}
inputState={inputState}
setInputState={setInputState}
onChange={onChange}
renderItem={(props) => (
<div className={s.DropdownPanelItem}>
<Text size="s" weight="bold" as="span">
{props.item.title}
</Text>
<Text size="s" as="span" className={s.DropdownPanelItem_id}>
{props.item.id}
</Text>
</div>
)}
>
<Button
text={tr('Create project')}
view="ghost"
iconLeft={<IconAddOutline size="s" />}
onClick={handleCreateProject}
className={s.CreateProjectButton}
/>
</DropdownPanel>
</Dropdown>
);
};

0 comments on commit 73794f9

Please sign in to comment.