Skip to content

Commit

Permalink
feat(Goal): allow user to delete goals
Browse files Browse the repository at this point in the history
  • Loading branch information
awinogradov committed Feb 15, 2023
1 parent 40295f6 commit da13117
Show file tree
Hide file tree
Showing 10 changed files with 292 additions and 19 deletions.
11 changes: 10 additions & 1 deletion i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@
"Set owner": "Set owner",
"Something went wrong 😿": "Something went wrong 😿",
"We are updating the goal": "We are updating the goal...",
"We are deleting the goal": "We are deleting the goal...",
"Deleted successfully 🎉": "Deleted successfully 🎉",
"Voila! Goal is up to date 🎉": "Voila! Goal is up to date 🎉",
"We are calling owner": "We are calling owner...",
"Voila! You are stargizer now 🎉": "Voila! You are stargizer now 🎉",
Expand All @@ -228,7 +230,8 @@
"Watching": "Watching",
"Stars": "Stars",
"Starred": "Starred",
"Edit goal": "Edit goal",
"Edit": "Edit",
"Delete": "Delete",
"New goal": "New goal",
"Priority": {
"Priority": "Priority",
Expand Down Expand Up @@ -399,5 +402,11 @@
"Medium": "Medium",
"Low": "Low",
"Lowest": "Lowest"
},
"GoalDeleteModal": {
"You are trying to delete goal": "You are trying to delete goal",
"To confirm deleting goal please type goal key below": "To confirm deleting goal <goal></goal> please type goal key below.",
"Yes, delete it": "Yes, delete it",
"Cancel": "Cancel"
}
}
11 changes: 10 additions & 1 deletion i18n/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@
"Set owner": "Исполнитель",
"Something went wrong 😿": "Упс! Что-то пошло не так 😿",
"We are updating new goal": "Погоди немного, обновляем цель...",
"We are deleting the goal": "Удаляем цель...",
"Deleted successfully 🎉": "Удалено 🎉",
"Voila! Goal is up to date 🎉": "Ура! Цель обновлена 🎉",
"We are calling owner": "Звоним владельцу...",
"Voila! You are stargizer now 🎉": "Норм! Цель в избранном 🎉",
Expand All @@ -228,7 +230,8 @@
"Watching": "Отписаться",
"Stars": "В избранное",
"Starred": "Избранное",
"Edit goal": "Редактировать",
"Edit": "Редактировать",
"Delete": "Удалить",
"New goal": "Создать цель",
"Priority": {
"Priority": "Приоритет",
Expand Down Expand Up @@ -396,5 +399,11 @@
"Medium": "Средний",
"Low": "Низкий",
"Lowest": "Самый низкий"
},
"GoalDeleteModal": {
"You are trying to delete goal": "Вы пытаетесь удалить цель",
"To confirm deleting goal please type goal key below": "Чтобы подтвердить удаление цели <goal></goal> введите ключ цели в поле ниже.",
"Yes, delete it": "Удалить цель",
"Cancel": "Отмена"
}
}
75 changes: 75 additions & 0 deletions src/components/GoalDeleteModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React, { ChangeEvent, useCallback, useState } from 'react';
import dynamic from 'next/dynamic';
import { useTranslations } from 'next-intl';

import { dispatchModalEvent, ModalEvent } from '../utils/dispatchModal';
import { danger0 } from '../design/@generated/themes';

import { ModalContent, ModalHeader } from './Modal';
import { FormTitle } from './FormTitle';
import { Text } from './Text';
import { Form } from './Form';
import { FormInput } from './FormInput';
import { FormAction, FormActions } from './FormActions';
import { Button } from './Button';

const ModalOnEvent = dynamic(() => import('./ModalOnEvent'));

interface GoalDeleteModalProps {
id: string;

onConfirm: () => void;
onCancel?: () => void;
}

export const GoalDeleteModal: React.FC<GoalDeleteModalProps> = ({ id, onConfirm, onCancel }) => {
const t = useTranslations('GoalDeleteModal');

const [deleteConfirmation, setDeleteConfirmation] = useState('');

const onConfirmationInputChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
setDeleteConfirmation(e.currentTarget.value);
}, []);

const onDeleteCancel = useCallback(() => {
setDeleteConfirmation('');
onCancel?.();
dispatchModalEvent(ModalEvent.GoalDeleteModal)();
}, [onCancel]);

return (
<ModalOnEvent view="danger" event={ModalEvent.GoalDeleteModal}>
<ModalHeader>
<FormTitle color={danger0}>{t('You are trying to delete goal')}</FormTitle>
</ModalHeader>

<ModalContent>
<Text>
{t.rich('To confirm deleting goal please type goal key below', {
goal: () => <b>{id}</b>,
})}
</Text>

<br />

<Form>
<FormInput flat="bottom" placeholder={id} autoComplete="off" onChange={onConfirmationInputChange} />

<FormActions flat="top">
<FormAction left />
<FormAction right inline>
<Button size="m" text={t('Cancel')} onClick={onDeleteCancel} />
<Button
size="m"
view="danger"
disabled={deleteConfirmation !== id}
onClick={onConfirm}
text={t('Yes, delete it')}
/>
</FormAction>
</FormActions>
</Form>
</ModalContent>
</ModalOnEvent>
);
};
80 changes: 75 additions & 5 deletions src/components/GoalPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { useTranslations } from 'next-intl';
import useSWR from 'swr';
import dynamic from 'next/dynamic';
import styled from 'styled-components';
import toast from 'react-hot-toast';

import { gql } from '../utils/gql';
import { Goal, State } from '../../graphql/@generated/genql';
import { gapM, gapS } from '../design/@generated/themes';
import { danger0, gapM, gapS } from '../design/@generated/themes';
import { goalFetcher, refreshInterval } from '../utils/entityFetcher';
import { nullable } from '../utils/nullable';
import { formatEstimate } from '../utils/dateTime';
Expand Down Expand Up @@ -37,11 +39,14 @@ import { Reactions } from './Reactions';
import ReactionsDropdown from './ReactionsDropdown';
import { Dot } from './Dot';
import { Icon } from './Icon';
import { MenuItem } from './MenuItem';
import { GoalDeleteModal } from './GoalDeleteModal';

const StateSwitch = dynamic(() => import('./StateSwitch'));
const CommentCreateForm = dynamic(() => import('./CommentCreateForm'));
const ModalOnEvent = dynamic(() => import('./ModalOnEvent'));
const GoalEditForm = dynamic(() => import('./GoalEditForm'));
const Dropdown = dynamic(() => import('./Dropdown'));

interface GoalPreviewProps {
goal: Goal;
Expand Down Expand Up @@ -143,6 +148,36 @@ const GoalPreview: React.FC<GoalPreviewProps> = ({ goal: partialGoal, visible, o
onClose?.();
}, [onClose]);

const onEditMenuChange = useCallback((item: { onClick: () => void }) => {
item.onClick?.();
}, []);

const onGoalDeleteConfirm = useCallback(async () => {
const promise = gql.mutation({
toggleGoalArchive: [
{
data: {
id: goal.id,
archived: true,
},
},
{
id: true,
},
],
});

toast.promise(promise, {
error: t('Something went wrong 😿'),
loading: t('We are deleting the goal'),
success: t('Deleted successfully 🎉'),
});

await promise;

refresh();
}, [t, goal, refresh]);

return (
<>
<ModalPreview visible={visible} onClose={onPreviewClose}>
Expand Down Expand Up @@ -211,10 +246,41 @@ const GoalPreview: React.FC<GoalPreviewProps> = ({ goal: partialGoal, visible, o
</StyledPublicActions>

{nullable(isUserAllowedToEdit, () => (
<Button
ghost
iconLeft={<Icon noWrap type="edit" size="xs" />}
onClick={dispatchModalEvent(ModalEvent.GoalEditModal)}
<Dropdown
onChange={onEditMenuChange}
items={[
{
label: t('Edit'),
icon: <Icon type="edit" size="xxs" />,
onClick: dispatchModalEvent(ModalEvent.GoalEditModal),
},
{
label: t('Delete'),
color: danger0,
icon: <Icon type="bin" size="xxs" />,
onClick: dispatchModalEvent(ModalEvent.GoalDeleteModal),
},
]}
renderTrigger={({ ref, onClick }) => (
<Button
ref={ref}
ghost
iconLeft={<Icon noWrap type="moreVertical" size="xs" />}
onClick={onClick}
/>
)}
renderItem={({ item, cursor, index, onClick }) => (
<MenuItem
key={item.label}
ghost
color={item.color}
focused={cursor === index}
icon={item.icon}
onClick={onClick}
>
{item.label}
</MenuItem>
)}
/>
))}
</StyledImportantActions>
Expand Down Expand Up @@ -264,6 +330,10 @@ const GoalPreview: React.FC<GoalPreviewProps> = ({ goal: partialGoal, visible, o
<GoalEditForm goal={goal} onSubmit={onGoalEdit} />
</ModalOnEvent>
))}

{nullable(isUserAllowedToEdit, () => (
<GoalDeleteModal id={goal.id} onConfirm={onGoalDeleteConfirm} />
))}
</>
);
};
Expand Down
Loading

0 comments on commit da13117

Please sign in to comment.