Skip to content

Commit

Permalink
feat(GoalForm): harmony vision
Browse files Browse the repository at this point in the history
  • Loading branch information
DenisVorop committed Feb 27, 2024
1 parent 668aae3 commit deead26
Show file tree
Hide file tree
Showing 26 changed files with 406 additions and 387 deletions.
48 changes: 25 additions & 23 deletions src/components/CommentCreateForm/CommentCreateForm.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import React, { useState, useCallback, useMemo } from 'react';
import React, { useState, useCallback, useMemo, MutableRefObject } from 'react';
import styled from 'styled-components';
import { State } from '@prisma/client';
import { State as StateType } from '@prisma/client';
import { UserPic, nullable } from '@taskany/bricks';
import { IconDownSmallSolid, IconUpSmallSolid } from '@taskany/icons';
import { Button, Dropdown, DropdownPanel, DropdownTrigger } from '@taskany/bricks/harmony';
import { Button, State } from '@taskany/bricks/harmony';

import { commentFormSubmitButton } from '../../utils/domObjects';
import { usePageContext } from '../../hooks/usePageContext';
import { GoalCommentFormSchema } from '../../schema/goal';
import { CommentSchema } from '../../schema/comment';
import { CommentForm } from '../CommentForm/CommentForm';
import { ActivityFeedItem } from '../ActivityFeed';
import { ColorizedMenuItem } from '../ColorizedMenuItem';
import { StateDot } from '../StateDot';
import { useLatest } from '../../hooks/useLatest';
import { Dropdown, DropdownPanel, DropdownTrigger } from '../Dropdown/Dropdown';
import { StateWrapper } from '../StateWrapper';

import { tr } from './CommentCreateForm.i18n';

interface CommentCreateFormProps extends Omit<React.ComponentProps<typeof CommentForm>, 'actionButton'> {
states?: State[];
states?: StateType[];
stateId?: string | null;

onSubmit: (comment: GoalCommentFormSchema) => void;
Expand All @@ -42,7 +43,7 @@ const CommentCreateForm: React.FC<CommentCreateFormProps> = ({
const statesMap = useMemo(() => {
if (!states) return {};

return states.reduce<Record<string, State>>((acc, cur) => {
return states.reduce<Record<string, StateType>>((acc, cur) => {
acc[cur.id] = cur;
return acc;
}, {});
Expand Down Expand Up @@ -94,7 +95,7 @@ const CommentCreateForm: React.FC<CommentCreateFormProps> = ({
}, [onCancel, stateId, statesMap]);

const onStateSelect = useCallback(
(state: State) => {
(state: StateType) => {
setPushState((prev) => {
const newState = state.id === prev?.id ? undefined : state;
onChange?.({ description: descriptionRef.current, stateId: newState?.id });
Expand Down Expand Up @@ -149,37 +150,38 @@ const CommentCreateForm: React.FC<CommentCreateFormProps> = ({
iconLeft={pushState ? <StateDot hue={pushState.hue} /> : undefined}
{...commentFormSubmitButton.attr}
/>
<Dropdown hideOnClick>
<Dropdown>
<DropdownTrigger
arrow={false}
renderTrigger={(props) => (
<Button
brick="left"
type="button"
onClick={props.onClick}
iconRight={
props.isOpen ? (
<IconUpSmallSolid size="s" />
) : (
<IconDownSmallSolid size="s" />
)
}
ref={props.ref}
onClick={props.onClick}
ref={props.ref as MutableRefObject<HTMLButtonElement>}
/>
)}
/>
<DropdownPanel placement="top-end" arrow>
{list.map((state) => (
<ColorizedMenuItem
key={state.id}
hue={state.hue}
checked={state.id === pushState?.id}
onClick={() => onStateSelect(state)}
>
{state.title}
</ColorizedMenuItem>
))}
</DropdownPanel>
<DropdownPanel
placement="top-end"
items={list}
onChange={onStateSelect}
renderItem={(props) => (
<StateWrapper hue={props.item?.hue}>
<State
color="var(--state-stroke)"
title={props.item?.title}
onClick={() => onStateSelect(props.item)}
/>
</StateWrapper>
)}
/>
</Dropdown>
</StyledStateUpdate>
))}
Expand Down
5 changes: 2 additions & 3 deletions src/components/FormActions/FormActions.module.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.FormActions {
display: grid;
grid-template-columns: 8fr 4fr;
align-items: center;
display: flex;
gap: var(--gap-sm);
}
9 changes: 9 additions & 0 deletions src/components/GoalCreateForm/GoalCreateForm.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.FormControl {
display: flex;
align-items: center;
}

.MenuItem {
text-align: left;
max-width: 240px;
}
80 changes: 45 additions & 35 deletions src/components/GoalCreateForm/GoalCreateForm.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useCallback, useMemo, useState } from 'react';
import styled from 'styled-components';
import { MutableRefObject, useCallback, useMemo, useState } from 'react';
import { gray9 } from '@taskany/colors';
import { MenuItem, Text } from '@taskany/bricks';
import { IconUpSmallSolid, IconDownSmallSolid } from '@taskany/icons';
import { Button, Dropdown, DropdownPanel, DropdownTrigger } from '@taskany/bricks/harmony';
import { Button, Text } from '@taskany/bricks/harmony';
import { KeyCode, useKeyboard } from '@taskany/bricks';

import { useRouter } from '../../hooks/router';
import { usePageContext } from '../../hooks/usePageContext';
Expand All @@ -23,14 +22,11 @@ import {
goalCancelButton,
goalForm,
} from '../../utils/domObjects';
import RotatableTip from '../RotatableTip/RotatableTip';
import { FormActions } from '../FormActions/FormActions';
import { Dropdown, DropdownPanel, DropdownTrigger } from '../Dropdown/Dropdown';

import { tr } from './GoalCreateForm.i18n';

const StyledMenuItem = styled(MenuItem)`
text-align: left;
max-width: 240px;
`;
import s from './GoalCreateForm.module.css';

interface GoalCreateFormProps {
project?: {
Expand All @@ -56,21 +52,25 @@ const GoalCreateForm: React.FC<GoalCreateFormProps> = ({ title, onGoalCreate, pr
const { goalCreate } = useGoalResource({});
const { data: priorities } = trpc.priority.getAll.useQuery();
const defaultPriority = useMemo(() => priorities?.filter((priority) => priority.default)[0], [priorities]);
const [isOpen, setIsOpen] = useState(false);

const createOptions = [
{
id: '1',
title: tr('Create & Go'),
clue: tr('Create and go to the goal page'),
value: 1,
attr: goalActionCreateAndGo.attr,
},
{
id: '2',
title: tr('Create one more'),
clue: tr('Create and open new form for the next goal'),
value: 2,
attr: goalActionCreateOneMore.attr,
},
{
id: '3',
title: tr('Create only'),
clue: tr('Create goal and close form'),
value: 3,
Expand Down Expand Up @@ -133,6 +133,14 @@ const GoalCreateForm: React.FC<GoalCreateFormProps> = ({ title, onGoalCreate, pr
onGoalCreate?.(res);
};

const onCloseActions = useCallback(() => {
setIsOpen(false);
}, []);

const [onESC] = useKeyboard([KeyCode.Escape], () => {
onCloseActions();
});

return (
<GoalForm
busy={busy}
Expand All @@ -144,64 +152,66 @@ const GoalCreateForm: React.FC<GoalCreateFormProps> = ({ title, onGoalCreate, pr
onSubmit={createGoal}
title={title}
actionButton={
<>
<FormActions>
<Button
text={tr('Cancel')}
size="m"
onClick={dispatchModalEvent(ModalEvent.GoalCreateModal)}
{...goalCancelButton.attr}
/>
<>
<div className={s.FormControl} {...combobox.attr}>
<Button
view="primary"
disabled={busy}
type="submit"
brick="right"
size="m"
text={createOptions[createGoalType - 1].title}
{...createOptions[createGoalType - 1].attr}
/>
<Dropdown {...combobox.attr} hideOnClick>
<Dropdown isOpen={isOpen} onClose={onCloseActions}>
<DropdownTrigger
arrow={false}
renderTrigger={(props) => (
<Button
view="primary"
brick="left"
ref={props.ref}
onClick={props.onClick}
size="m"
ref={props.ref as MutableRefObject<HTMLButtonElement>}
onClick={() => {
setIsOpen(true);
props.onClick();
}}
iconRight={
props.isOpen ? (
<IconUpSmallSolid size="s" />
) : (
<IconDownSmallSolid size="s" />
)
}
{...(isOpen ? onESC : {})}
{...createActionToggle.attr}
/>
)}
/>
<DropdownPanel placement="top-end" arrow>
{createOptions.map((option) => (
<StyledMenuItem
view="primary"
key={option.title}
ghost
{...option.attr}
onClick={() => onCreateTypeChange(option)}
>
<Text>{option.title}</Text>
{option.clue && (
<Text size="xs" color={gray9}>
{option.clue}
<DropdownPanel
placement="top-end"
items={createOptions}
onChange={onCreateTypeChange}
renderItem={(props) => (
<div onClick={() => onCreateTypeChange(props.item)} className={s.MenuItem}>
<Text size="m">{props.item.title}</Text>
{props.item.clue && (
<Text size="s" color={gray9}>
{props.item.clue}
</Text>
)}
</StyledMenuItem>
))}
</DropdownPanel>
</div>
)}
/>
</Dropdown>
</>
</>
</div>
</FormActions>
}
tip={<RotatableTip context="goal" />}
{...goalForm.attr}
/>
);
Expand Down
10 changes: 5 additions & 5 deletions src/components/GoalEditForm/GoalEditForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useGoalResource } from '../../hooks/useGoalResource';
import { getDateStringFromEstimate } from '../../utils/dateTime';
import { goalForm, goalUpdateButton } from '../../utils/domObjects';
import { dispatchPreviewUpdateEvent, useGoalPreview } from '../GoalPreview/GoalPreviewProvider';
import RotatableTip from '../RotatableTip/RotatableTip';
import { FormActions } from '../FormActions/FormActions';

import { tr } from './GoalEditForm.i18n';

Expand Down Expand Up @@ -96,18 +96,18 @@ const GoalEditForm: React.FC<GoalEditFormProps> = ({ goal, onSubmit }) => {
estimate={estimateValue}
onSubmit={updateGoal}
actionButton={
<>
<Button text={tr('Cancel')} onClick={dispatchModalEvent(ModalEvent.GoalEditModal)} />
<FormActions>
<Button text={tr('Cancel')} onClick={dispatchModalEvent(ModalEvent.GoalEditModal)} size="m" />
<Button
view="primary"
disabled={busy}
type="submit"
text={tr('Submit')}
size="m"
{...goalUpdateButton.attr}
/>
</>
</FormActions>
}
tip={<RotatableTip context="goal" />}
{...goalForm.attr}
/>
);
Expand Down
5 changes: 2 additions & 3 deletions src/components/GoalForm/GoalForm.i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
{
"Goal's title": "Goal title",
"And its description": "Goal description",
"Assign": "Assign",
"Enter name or email": "Name/Email",
"Enter project": "Project",
"State": "State",
"Enter tag title": "Enter tag title",
"Priority": "Priority"
"Personal goal": "",
"Project goal": ""
}
5 changes: 2 additions & 3 deletions src/components/GoalForm/GoalForm.i18n/ru.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
{
"Assign": "Ответственный",
"Enter name or email": "Имя/Почта",
"Enter project": "Проект",
"State": "Статус",
"Enter tag title": "Название тэга",
"Goal's title": "Название цели",
"And its description": "Описание цели",
"Priority": "Приоритет"
"Personal goal": "Личная цель",
"Project goal": "Проектная цель"
}
17 changes: 17 additions & 0 deletions src/components/GoalForm/GoalForm.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,20 @@
flex-direction: column;
gap: var(--gap-m);
}

.FormActions {
justify-content: space-between;
}

.SwitchGoalType {
display: flex;
align-items: center;
gap: var(--gap-sm);
}

.FormTip {
display: flex;
align-items: center;
max-width: 380px;
margin-left: auto;
}
Loading

0 comments on commit deead26

Please sign in to comment.