Skip to content

Commit ec4b19c

Browse files
committed
feat: delete tags
1 parent 2813ed0 commit ec4b19c

File tree

5 files changed

+153
-13
lines changed

5 files changed

+153
-13
lines changed

apps/backend/src/api/routes/posts.controller.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ export class PostsController {
8181
return this._postsService.editTag(id, org.id, body);
8282
}
8383

84+
@Delete('/tags/:id')
85+
async deleteTag(
86+
@GetOrgFromRequest() org: Organization,
87+
@Param('id') id: string
88+
) {
89+
return this._postsService.deleteTag(id, org.id);
90+
}
91+
8492
@Get('/')
8593
async getPosts(
8694
@GetOrgFromRequest() org: Organization,

apps/frontend/src/app/global.scss

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,9 @@ html[dir='rtl'] [dir='ltr'] {
745745
}
746746

747747
.post-now {
748-
box-shadow: -33px 57px 18px 0 rgba(0, 0, 0, 0.01), -21px 36px 17px 0 rgba(0, 0, 0, 0.06), -12px 20px 14px 0 rgba(0, 0, 0, 0.20), -5px 9px 11px 0 rgba(0, 0, 0, 0.34), -1px 2px 6px 0 rgba(0, 0, 0, 0.39);
748+
box-shadow: -33px 57px 18px 0 rgba(0, 0, 0, 0.01),
749+
-21px 36px 17px 0 rgba(0, 0, 0, 0.06), -12px 20px 14px 0 rgba(0, 0, 0, 0.2),
750+
-5px 9px 11px 0 rgba(0, 0, 0, 0.34), -1px 2px 6px 0 rgba(0, 0, 0, 0.39);
749751
}
750752

751753
.uppyChange .uppy-Dashboard-inner {
@@ -780,4 +782,9 @@ html[dir='rtl'] [dir='ltr'] {
780782
.forceChange .changeColor {
781783
background: var(--new-btn-primary) !important;
782784
color: #fff !important;
783-
}
785+
}
786+
787+
.text-shadow-tags {
788+
text-shadow: -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black,
789+
1px 1px 0 black;
790+
}

apps/frontend/src/components/launches/tags.component.tsx

Lines changed: 119 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ import { useT } from '@gitroom/react/translation/get.transation.service.client';
1212
import { useClickOutside } from '@mantine/hooks';
1313
import clsx from 'clsx';
1414
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
15-
import { TagIcon, DropdownArrowIcon, PlusIcon, CheckmarkIcon } from '@gitroom/frontend/components/ui/icons';
15+
import {
16+
TagIcon,
17+
DropdownArrowIcon,
18+
PlusIcon,
19+
CheckmarkIcon,
20+
} from '@gitroom/frontend/components/ui/icons';
1621

1722
export const TagsComponent: FC<{
1823
name: string;
@@ -54,7 +59,9 @@ export const TagsComponentInner: FC<{
5459
}) => void;
5560
}> = ({ initial, onChange, name, mutate, allTags: data }) => {
5661
const t = useT();
62+
const fetch = useFetch();
5763
const [isOpen, setIsOpen] = useState(false);
64+
const [allowClose, setAllowClose] = useState(true);
5865
const [tagValue, setTagValue] = useState<any[]>(
5966
(initial?.slice(0) || []).map((p: any) => {
6067
return data?.tags.find((a: any) => a.name === p.value) || p;
@@ -63,7 +70,7 @@ export const TagsComponentInner: FC<{
6370
const modals = useModals();
6471

6572
const ref = useClickOutside(() => {
66-
if (!isOpen) {
73+
if (!isOpen || !allowClose) {
6774
return;
6875
}
6976
setIsOpen(false);
@@ -98,6 +105,58 @@ export const TagsComponentInner: FC<{
98105
}
99106
}, []);
100107

108+
const deleteTag = useCallback(
109+
async (tag: any, e: React.MouseEvent) => {
110+
setAllowClose(false);
111+
e.stopPropagation();
112+
const confirmed: boolean = await new Promise((resolve) => {
113+
modals.openModal({
114+
title: t('delete_tag', 'Delete Tag'),
115+
children: (close) => (
116+
<ConfirmDeleteModal
117+
tagName={tag.name}
118+
close={close}
119+
resolve={resolve}
120+
/>
121+
),
122+
});
123+
});
124+
125+
if (!confirmed) {
126+
setTimeout(() => {
127+
setAllowClose(true);
128+
}, 500);
129+
return;
130+
}
131+
132+
await fetch(`/posts/tags/${tag.id}`, {
133+
method: 'DELETE',
134+
});
135+
136+
// Remove the tag from current selection if it was selected
137+
const modify = tagValue.filter((a) => a.id !== tag.id);
138+
if (modify.length !== tagValue.length) {
139+
setTagValue(modify);
140+
onChange({
141+
target: {
142+
value: modify.map((p: any) => ({
143+
label: p.name,
144+
value: p.name,
145+
})),
146+
name,
147+
},
148+
});
149+
}
150+
151+
await mutate();
152+
153+
setTimeout(() => {
154+
setAllowClose(true);
155+
}, 500);
156+
},
157+
[tagValue, name, onChange, mutate, fetch, modals, t]
158+
);
159+
101160
return (
102161
<div
103162
ref={ref}
@@ -122,7 +181,7 @@ export const TagsComponentInner: FC<{
122181
className="h-full flex justify-center items-center px-[8px] rounded-[4px]"
123182
style={{ backgroundColor: tagValue[0].color }}
124183
>
125-
<span className="mix-blend-difference text-[#fff]">
184+
<span className="text-shadow-tags text-[#fff]">
126185
{tagValue[0].name}
127186
</span>
128187
</div>
@@ -158,20 +217,28 @@ export const TagsComponentInner: FC<{
158217
});
159218
}}
160219
key={p.name}
161-
className="h-[40px] py-[8px] px-[20px] -mx-[12px] flex gap-[8px]"
220+
className="min-h-[40px] py-[8px] px-[20px] -mx-[12px] flex gap-[8px] items-center group"
162221
>
163222
<Check
164223
onChange={() => {}}
165224
value={!!tagValue.find((a) => a.id === p.id)}
166225
/>
167-
<div
168-
className="h-full flex justify-center items-center px-[8px] rounded-[8px]"
169-
style={{ backgroundColor: p.color }}
170-
>
171-
<span className="mix-blend-difference text-[#fff]">
226+
<div className="h-full flex items-center flex-1 break-all">
227+
<span
228+
className="text-[#fff] px-[8px] rounded-[8px] text-shadow-tags"
229+
style={{ backgroundColor: p.color }}
230+
>
172231
{p.name}
173232
</span>
174233
</div>
234+
{!tagValue.find((a) => a.id === p.id) && (
235+
<div
236+
onClick={(e) => deleteTag(p, e)}
237+
className="ms-auto transition-opacity cursor-pointer text-red-500 text-[14px] font-[600]"
238+
>
239+
×
240+
</div>
241+
)}
175242
</div>
176243
))}
177244
<div
@@ -181,7 +248,9 @@ export const TagsComponentInner: FC<{
181248
<div>
182249
<PlusIcon />
183250
</div>
184-
<div className="text-[13px] font-[600]">{t('add_new_tag', 'Add New Tag')}</div>
251+
<div className="text-[13px] font-[600]">
252+
{t('add_new_tag', 'Add New Tag')}
253+
</div>
185254
</div>
186255
</div>
187256
)}
@@ -197,7 +266,7 @@ const Check: FC<{ value: boolean; onChange: (value: boolean) => void }> = ({
197266
<div
198267
onClick={() => onChange(!value)}
199268
className={clsx(
200-
'text-[10px] font-[500] text-center flex border border-btnSimple rounded-[6px] w-[20px] h-[20px] justify-center items-center',
269+
'text-[10px] font-[500] text-center flex border border-btnSimple rounded-[6px] min-w-[20px] min-h-[20px] w-[20px] h-[20px] justify-center items-center',
201270
value && 'bg-[#612BD3]'
202271
)}
203272
>
@@ -403,6 +472,45 @@ export const TagsComponentA: FC<{
403472
</>
404473
);
405474
};
475+
const ConfirmDeleteModal: FC<{
476+
tagName: string;
477+
close: () => void;
478+
resolve: (value: boolean) => void;
479+
}> = ({ tagName, close, resolve }) => {
480+
const t = useT();
481+
482+
return (
483+
<div className="flex flex-col gap-[16px]">
484+
<p className="text-[14px]">
485+
{t(
486+
'confirm_delete_tag',
487+
'Are you sure you want to delete the tag "{{tagName}}"?',
488+
{ tagName }
489+
)}
490+
</p>
491+
<div className="flex gap-[8px] justify-end">
492+
<Button
493+
onClick={() => {
494+
resolve(false);
495+
close();
496+
}}
497+
>
498+
{t('cancel', 'Cancel')}
499+
</Button>
500+
<Button
501+
onClick={() => {
502+
resolve(true);
503+
close();
504+
}}
505+
className="bg-red-500 hover:bg-red-600"
506+
>
507+
{t('delete', 'Delete')}
508+
</Button>
509+
</div>
510+
</div>
511+
);
512+
};
513+
406514
const ShowModal: FC<{
407515
tag: string;
408516
color?: string;

libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,7 @@ export class PostsRepository {
678678
return this._tags.model.tags.findMany({
679679
where: {
680680
orgId,
681+
deletedAt: null,
681682
},
682683
});
683684
}
@@ -704,6 +705,18 @@ export class PostsRepository {
704705
});
705706
}
706707

708+
deleteTag(id: string, orgId: string) {
709+
return this._tags.model.tags.update({
710+
where: {
711+
id,
712+
orgId,
713+
},
714+
data: {
715+
deletedAt: new Date(),
716+
},
717+
});
718+
}
719+
707720
createComment(
708721
orgId: string,
709722
userId: string,

libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,10 @@ export class PostsService {
841841
return this._postRepository.editTag(id, orgId, body);
842842
}
843843

844+
deleteTag(id: string, orgId: string) {
845+
return this._postRepository.deleteTag(id, orgId);
846+
}
847+
844848
createComment(
845849
orgId: string,
846850
userId: string,

0 commit comments

Comments
 (0)