remove remark
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
hamid zarghami
2026-07-25 11:19:08 +03:30
parent 42528f4d5c
commit c9713a93ac
7 changed files with 95 additions and 8 deletions
+19 -2
View File
@@ -1,4 +1,5 @@
import { FC, Fragment, ReactNode, useEffect } from 'react' import { FC, Fragment, ReactNode, useEffect } from 'react'
import { clx } from '../helpers/utils'
import HeaderModal from './HeaderModal' import HeaderModal from './HeaderModal'
interface Props { interface Props {
@@ -8,6 +9,8 @@ interface Props {
isHeader?: boolean, isHeader?: boolean,
title_header?: string, title_header?: string,
width?: number width?: number
/** Raise above popovers (z-80) when confirm opens from nested panels */
elevated?: boolean
} }
const DefaulModal: FC<Props> = (props: Props) => { const DefaulModal: FC<Props> = (props: Props) => {
@@ -26,7 +29,14 @@ const DefaulModal: FC<Props> = (props: Props) => {
{ {
props.open && ( props.open && (
<Fragment> <Fragment>
<div style={{ maxWidth: props.width }} className='xl:justify-center xl:items-center items-end flex overflow-hidden fixed inset-0 z-[60] h-auto top-0 bottom-0 m-auto outline-none focus:outline-none xl:max-w-xl mx-auto'> <div
style={{ maxWidth: props.width }}
onPointerDown={(e) => e.stopPropagation()}
className={clx(
'xl:justify-center xl:items-center items-end flex overflow-hidden fixed inset-0 h-auto top-0 bottom-0 m-auto outline-none focus:outline-none xl:max-w-xl mx-auto',
props.elevated ? 'z-[100]' : 'z-[60]',
)}
>
<div className='relative max-h-[85vh] bottom-0 left-0 flex xl:items-center items-end w-full xl:my-6 xl:p-2'> <div className='relative max-h-[85vh] bottom-0 left-0 flex xl:items-center items-end w-full xl:my-6 xl:p-2'>
<div className='border-0 max-h-[85vh] p-5 lg:min-w-full overflow-y-auto rounded-3xl rounded-b-none xl:rounded-b-3xl relative flex flex-col w-full modalGlass2 outline-none focus:outline-none'> <div className='border-0 max-h-[85vh] p-5 lg:min-w-full overflow-y-auto rounded-3xl rounded-b-none xl:rounded-b-3xl relative flex flex-col w-full modalGlass2 outline-none focus:outline-none'>
@@ -46,7 +56,14 @@ const DefaulModal: FC<Props> = (props: Props) => {
</div> </div>
</div> </div>
<div onClick={props.close} className='fixed size-full top-0 bottom-0 right-0 modalGlass inset-0 z-50 '></div> <div
onClick={props.close}
onPointerDown={(e) => e.stopPropagation()}
className={clx(
'fixed size-full top-0 bottom-0 right-0 modalGlass inset-0',
props.elevated ? 'z-[90]' : 'z-50',
)}
/>
</Fragment> </Fragment>
) )
} }
+6 -3
View File
@@ -1,7 +1,8 @@
import { FC, useState } from 'react' import { FC, useState } from 'react'
import DefaulModal from './DefaulModal' import { createPortal } from 'react-dom'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Button from './Button' import Button from './Button'
import DefaulModal from './DefaulModal'
import Textarea from './Textarea' import Textarea from './Textarea'
type Props = { type Props = {
@@ -18,12 +19,13 @@ const ModalConfrim: FC<Props> = (props: Props) => {
const { t } = useTranslation('global') const { t } = useTranslation('global')
const [description, setDescription] = useState<string>('') const [description, setDescription] = useState<string>('')
return ( return createPortal(
<DefaulModal <DefaulModal
open={props.isOpen} open={props.isOpen}
close={props.close} close={props.close}
title_header={t('confrim.subject')} title_header={t('confrim.subject')}
isHeader isHeader
elevated
> >
<div className='mt-6'> <div className='mt-6'>
<div className='text-sm text-center'> <div className='text-sm text-center'>
@@ -60,7 +62,8 @@ const ModalConfrim: FC<Props> = (props: Props) => {
/> />
</div> </div>
</div> </div>
</DefaulModal> </DefaulModal>,
document.body,
) )
} }
@@ -17,7 +17,13 @@ import TaskDetailTimePopover from "./time/TaskDetailTimePopover";
import type { TaskUser } from "./users/types"; import type { TaskUser } from "./users/types";
import type { UserItemType } from "../../../users/types/UserTypes"; import type { UserItemType } from "../../../users/types/UserTypes";
import type { TaskDetailType } from "../../task/types/TaskTypes"; import type { TaskDetailType } from "../../task/types/TaskTypes";
import { useCreateCheckListItem, useCreateTaskAttachment, useCreateTaskRemark, useUpdateTask } from "../../task/hooks/useTaskData"; import {
useCreateCheckListItem,
useCreateTaskAttachment,
useCreateTaskRemark,
useDeleteTaskRemark,
useUpdateTask,
} from "../../task/hooks/useTaskData";
import { useSingleUpload } from "../../../service/hooks/useServiceData"; import { useSingleUpload } from "../../../service/hooks/useServiceData";
import { ErrorType } from "../../../../helpers/types"; import { ErrorType } from "../../../../helpers/types";
@@ -31,6 +37,7 @@ type Props = {
const TaskDetailToolbar: FC<Props> = ({ activeTab, onTabChange, taskDetail, taskId }) => { const TaskDetailToolbar: FC<Props> = ({ activeTab, onTabChange, taskDetail, taskId }) => {
const { t } = useTranslation("global"); const { t } = useTranslation("global");
const createTaskRemark = useCreateTaskRemark(); const createTaskRemark = useCreateTaskRemark();
const deleteTaskRemark = useDeleteTaskRemark();
const createCheckListItem = useCreateCheckListItem(); const createCheckListItem = useCreateCheckListItem();
const createTaskAttachment = useCreateTaskAttachment(); const createTaskAttachment = useCreateTaskAttachment();
const singleUpload = useSingleUpload(); const singleUpload = useSingleUpload();
@@ -224,6 +231,29 @@ const TaskDetailToolbar: FC<Props> = ({ activeTab, onTabChange, taskDetail, task
); );
}; };
const handleDeleteLabel = (id: string) => {
const effectiveTaskId = taskId || taskDetail?.id;
if (!effectiveTaskId) return;
deleteTaskRemark.mutate(
{ id, taskId: effectiveTaskId },
{
onSuccess: () => {
setLabels((prev) => prev.filter((label) => label.id !== id));
setSelectedLabelIds((prev) => {
const next = new Set(prev);
next.delete(id);
return next;
});
toast(t("success"), "success");
},
onError: (error: ErrorType) => {
toast(error.response?.data?.error.message[0], "error");
},
},
);
};
const handleChecklistClose = () => { const handleChecklistClose = () => {
if (isChecklistOpen) onTabChange("checklist"); if (isChecklistOpen) onTabChange("checklist");
}; };
@@ -338,7 +368,9 @@ const TaskDetailToolbar: FC<Props> = ({ activeTab, onTabChange, taskDetail, task
onViewChange={setLabelsView} onViewChange={setLabelsView}
onToggle={handleLabelToggle} onToggle={handleLabelToggle}
onCreate={handleCreate} onCreate={handleCreate}
onDelete={handleDeleteLabel}
isSubmitting={createTaskRemark.isPending} isSubmitting={createTaskRemark.isPending}
isDeleting={deleteTaskRemark.isPending}
/> />
) : null ) : null
} }
@@ -2,6 +2,7 @@ import { AddCircle, Edit } from "iconsax-react";
import { type FC } from "react"; import { type FC } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Button from "../../../../../components/Button"; import Button from "../../../../../components/Button";
import TrashWithConfrim from "../../../../../components/TrashWithConfrim";
import TaskDetailLabelCheckbox from "./TaskDetailLabelCheckbox"; import TaskDetailLabelCheckbox from "./TaskDetailLabelCheckbox";
import type { TaskLabel } from "./types"; import type { TaskLabel } from "./types";
@@ -10,10 +11,20 @@ type Props = {
selectedIds: Set<string>; selectedIds: Set<string>;
onToggle: (id: string) => void; onToggle: (id: string) => void;
onEdit: (label: TaskLabel) => void; onEdit: (label: TaskLabel) => void;
onDelete: (id: string) => void;
onCreateClick: () => void; onCreateClick: () => void;
isDeleting?: boolean;
}; };
const TaskDetailLabelsList: FC<Props> = ({ labels, selectedIds, onToggle, onEdit, onCreateClick }) => { const TaskDetailLabelsList: FC<Props> = ({
labels,
selectedIds,
onToggle,
onEdit,
onDelete,
onCreateClick,
isDeleting = false,
}) => {
const { t } = useTranslation("global"); const { t } = useTranslation("global");
return ( return (
@@ -32,7 +43,8 @@ const TaskDetailLabelsList: FC<Props> = ({ labels, selectedIds, onToggle, onEdit
{label.title && <span className="text-xs font-medium truncate">{label.title}</span>} {label.title && <span className="text-xs font-medium truncate">{label.title}</span>}
</div> </div>
<Edit onClick={() => onEdit(label)} size={16} color="#0047FF" /> <Edit onClick={() => onEdit(label)} size={16} color="#0047FF" className="shrink-0 cursor-pointer" />
<TrashWithConfrim onDelete={() => onDelete(label.id)} isLoading={isDeleting} size={16} color="#FF0000" />
</div> </div>
); );
})} })}
@@ -10,7 +10,9 @@ type Props = {
onViewChange: (view: LabelsView) => void; onViewChange: (view: LabelsView) => void;
onToggle: (id: string) => void; onToggle: (id: string) => void;
onCreate: (title: string, color: string) => void; onCreate: (title: string, color: string) => void;
onDelete: (id: string) => void;
isSubmitting?: boolean; isSubmitting?: boolean;
isDeleting?: boolean;
}; };
const TaskDetailLabelsPopover: FC<Props> = ({ const TaskDetailLabelsPopover: FC<Props> = ({
@@ -20,7 +22,9 @@ const TaskDetailLabelsPopover: FC<Props> = ({
onViewChange, onViewChange,
onToggle, onToggle,
onCreate, onCreate,
onDelete,
isSubmitting = false, isSubmitting = false,
isDeleting = false,
}) => { }) => {
return ( return (
<> <>
@@ -30,7 +34,9 @@ const TaskDetailLabelsPopover: FC<Props> = ({
selectedIds={selectedIds} selectedIds={selectedIds}
onToggle={onToggle} onToggle={onToggle}
onEdit={() => undefined} onEdit={() => undefined}
onDelete={onDelete}
onCreateClick={() => onViewChange("create")} onCreateClick={() => onViewChange("create")}
isDeleting={isDeleting}
/> />
) : ( ) : (
<TaskDetailNewLabelForm <TaskDetailNewLabelForm
@@ -119,6 +119,18 @@ export const useCreateTaskRemark = () => {
}); });
}; };
export const useDeleteTaskRemark = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id }: { id: string; taskId: string }) => api.deleteTaskRemark(id),
onSuccess: (_data, variables) => {
queryClient.invalidateQueries({ queryKey: ["task-detail", variables.taskId] });
queryClient.invalidateQueries({ queryKey: ["project"] });
},
});
};
export const useCreateCheckListItem = () => { export const useCreateCheckListItem = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
@@ -64,6 +64,11 @@ export const createTaskRemark = async (params: CreateTaskRemarkType): Promise<Cr
return data; return data;
}; };
export const deleteTaskRemark = async (id: string) => {
const { data } = await axios.delete(`/task-manager/remarks/${id}`);
return data;
};
export const createCheckListItem = async (params: CreateCheckListItemType): Promise<CreateCheckListItemResponse> => { export const createCheckListItem = async (params: CreateCheckListItemType): Promise<CreateCheckListItemResponse> => {
const { data } = await axios.post(`/task-manager/check-list-items`, params); const { data } = await axios.post(`/task-manager/check-list-items`, params);
return data; return data;