diff --git a/apps/mobile/yarn.lock b/apps/mobile/yarn.lock index 099182d3a..a84f0e5fb 100644 --- a/apps/mobile/yarn.lock +++ b/apps/mobile/yarn.lock @@ -15057,9 +15057,9 @@ webidl-conversions@^7.0.0: integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== webpack-dev-middleware@^5.3.1: - version "5.3.3" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" - integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + version "5.3.4" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517" + integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== dependencies: colorette "^2.0.10" memfs "^3.4.3" diff --git a/apps/web/app/[locale]/kanban/page.tsx b/apps/web/app/[locale]/kanban/page.tsx index 1b4e76c8c..98bb89d51 100644 --- a/apps/web/app/[locale]/kanban/page.tsx +++ b/apps/web/app/[locale]/kanban/page.tsx @@ -18,12 +18,34 @@ import { AddIcon, PeoplesIcon } from 'assets/svg'; import { InviteFormModal } from 'lib/features/team/invite/invite-form-modal'; import { userTimezone } from '@app/helpers'; import KanbanSearch from '@components/pages/kanban/search-bar'; -import { EpicPropertiesDropdown, TaskLabelsDropdown, TaskPropertiesDropdown, TaskSizesDropdown } from 'lib/features'; +import { + EpicPropertiesDropdown, + StatusDropdown, + TStatusItem, + TaskLabelsDropdown, + TaskPropertiesDropdown, + TaskSizesDropdown, + taskIssues, + useStatusValue +} from 'lib/features'; import { useRecoilValue } from 'recoil'; import { fullWidthState } from '@app/stores/fullWidth'; +import { CircleIcon } from 'lucide-react'; +import { XMarkIcon } from '@heroicons/react/20/solid'; const Kanban = () => { - const { data, setSearchTasks, searchTasks, isLoading, setPriority, setSizes, setLabels, setEpics } = useKanban(); + const { + data, + setSearchTasks, + searchTasks, + isLoading, + setPriority, + setSizes, + setLabels, + setEpics, + setIssues, + issues + } = useKanban(); const { activeTeam, isTrackingEnabled } = useOrganizationTeams(); const t = useTranslations(); @@ -56,6 +78,11 @@ const Kanban = () => { const { user } = useAuthenticateUser(); const { openModal, isOpen, closeModal } = useModal(); const timezone = userTimezone(); + const { items } = useStatusValue<'issueType'>({ + status: taskIssues, + value: issues as any, + onValueChange: setIssues as any + }); return ( <> @@ -125,7 +152,49 @@ const Kanban = () => { multiple={true} /> + {/*
*/} +
+
+ +
+ {issues.icon ?? } +
+

{issues.name}

+
+ {issues.value && ( +
+ setIssues({ + name: 'Issues', + icon: null, + bgColor: '', + value: '' + }) + } + className="w-5 h-5 z-50 p-0.5 cursor-pointer" + > + +
+ )} +
+ { + setIssues(items.find((v) => v.name == e) as TStatusItem); + }} + issueType="issue" + /> +
+ {/*
*/}
setLabels(values || [])} @@ -150,7 +219,6 @@ const Kanban = () => {
-
diff --git a/apps/web/app/[locale]/profile/[memberId]/page.tsx b/apps/web/app/[locale]/profile/[memberId]/page.tsx index d2415ed75..ba39e11d6 100644 --- a/apps/web/app/[locale]/profile/[memberId]/page.tsx +++ b/apps/web/app/[locale]/profile/[memberId]/page.tsx @@ -28,13 +28,15 @@ type FilterTab = 'Tasks' | 'Screenshots' | 'Apps' | 'Visited Sites'; const Profile = React.memo(function ProfilePage({ params }: { params: { memberId: string } }) { const profile = useUserProfilePage(); const { user } = useAuthenticateUser(); - const { isTrackingEnabled, activeTeam } = useOrganizationTeams(); + const { isTrackingEnabled, activeTeam, activeTeamManagers } = useOrganizationTeams(); const fullWidth = useRecoilValue(fullWidthState); const [activityFilter, setActivityFilter] = useState('Tasks'); const setActivityTypeFilter = useSetRecoilState(activityTypeState); const hook = useTaskFilter(profile); - const canSeeActivity = profile.userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER'; + + const isManagerConnectedUser = activeTeamManagers.findIndex((member) => member.employee?.user?.id == user?.id); + const canSeeActivity = profile.userProfile?.id === user?.id || isManagerConnectedUser != -1; const t = useTranslations(); const breadcrumb = [ @@ -69,7 +71,7 @@ const Profile = React.memo(function ProfilePage({ params }: { params: { memberId return ( <> - + {/* Breadcrumb */}
diff --git a/apps/web/app/[locale]/settings/layout.tsx b/apps/web/app/[locale]/settings/layout.tsx index ffb07c97d..e71fc3db8 100644 --- a/apps/web/app/[locale]/settings/layout.tsx +++ b/apps/web/app/[locale]/settings/layout.tsx @@ -11,6 +11,7 @@ import Link from 'next/link'; import React from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; import { clsxm } from '@app/utils'; +import { withAuthentication } from 'lib/app/authenticator'; const SettingsLayout = ({ children }: { children: JSX.Element }) => { const t = useTranslations(); @@ -43,7 +44,7 @@ const SettingsLayout = ({ children }: { children: JSX.Element }) => { {/*
*/} - +
@@ -56,4 +57,4 @@ const SettingsLayout = ({ children }: { children: JSX.Element }) => { } }; -export default SettingsLayout; +export default withAuthentication(SettingsLayout, { displayName: 'Settings' }); diff --git a/apps/web/app/[locale]/settings/team/page.tsx b/apps/web/app/[locale]/settings/team/page.tsx index f99f5bc3a..2fee89912 100644 --- a/apps/web/app/[locale]/settings/team/page.tsx +++ b/apps/web/app/[locale]/settings/team/page.tsx @@ -34,7 +34,7 @@ const Team = () => { {/* General Settings */}
@@ -47,7 +47,7 @@ const Team = () => { {isTeamManager ? ( @@ -58,7 +58,7 @@ const Team = () => { {isTeamManager ? ( @@ -68,7 +68,7 @@ const Team = () => { {isTeamManager && ( @@ -78,7 +78,7 @@ const Team = () => { {/* Issues Settings */} @@ -96,7 +96,7 @@ const Team = () => { {/* Danger Zone */} diff --git a/apps/web/app/hooks/features/useKanban.ts b/apps/web/app/hooks/features/useKanban.ts index dfa0b797f..852e1a348 100644 --- a/apps/web/app/hooks/features/useKanban.ts +++ b/apps/web/app/hooks/features/useKanban.ts @@ -5,11 +5,18 @@ import { useEffect, useState } from 'react'; import { ITaskStatusItemList, ITeamTask } from '@app/interfaces'; import { useTeamTasks } from './useTeamTasks'; import { IKanban } from '@app/interfaces/IKanban'; +import { TStatusItem } from 'lib/features'; export function useKanban() { const [loading, setLoading] = useState(true); const [searchTasks, setSearchTasks] = useState(''); const [labels, setLabels] = useState([]); const [epics, setEpics] = useState([]); + const [issues, setIssues] = useState({ + name: 'Issues', + icon: null, + bgColor: '', + value: '' + }); const [kanbanBoard, setKanbanBoard] = useRecoilState(kanbanBoardState); const taskStatusHook = useTaskStatus(); const { tasks: newTask, tasksFetching, updateTask } = useTeamTasks(); @@ -26,6 +33,9 @@ export function useKanban() { .filter((task: ITeamTask) => { return priority.length ? priority.includes(task.priority) : true; }) + .filter((task: ITeamTask) => { + return issues.value ? task.issueType === issues.value : true; + }) .filter((task: ITeamTask) => { return sizes.length ? sizes.includes(task.size) : true; }) @@ -38,21 +48,21 @@ export function useKanban() { const getTasksByStatus = (status: string | undefined) => { return tasks.filter((task: ITeamTask) => { - return task.status === status; + return task.taskStatusId === status; }); }; taskStatusHook.taskStatus.map((taskStatus: ITaskStatusItemList) => { kanban = { ...kanban, - [taskStatus.name ? taskStatus.name : '']: getTasksByStatus(taskStatus.name) + [taskStatus.name ? taskStatus.name : '']: getTasksByStatus(taskStatus.id) }; }); setKanbanBoard(kanban); setLoading(false); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [taskStatusHook.loading, tasksFetching, newTask, searchTasks, priority, sizes, labels, epics]); + }, [taskStatusHook.loading, tasksFetching, newTask, searchTasks, priority, sizes, labels, epics, issues]); /** * collapse or show kanban column @@ -80,7 +90,7 @@ export function useKanban() { const reorderStatus = (itemStatus: string, index: number) => { taskStatusHook.taskStatus .filter((status: ITaskStatusItemList) => { - return status.name === itemStatus; + return status.id === itemStatus; }) .map((status: ITaskStatusItemList) => { taskStatusHook.editTaskStatus(status.id, { @@ -100,9 +110,11 @@ export function useKanban() { isLoading: loading, columns: taskStatusHook.taskStatus, searchTasks, + issues, setPriority, setLabels, setSizes, + setIssues, setEpics, updateKanbanBoard: setKanbanBoard, updateTaskStatus: updateTask, diff --git a/apps/web/app/hooks/features/useTaskInput.ts b/apps/web/app/hooks/features/useTaskInput.ts index 3d558a4d8..134168405 100644 --- a/apps/web/app/hooks/features/useTaskInput.ts +++ b/apps/web/app/hooks/features/useTaskInput.ts @@ -144,7 +144,7 @@ export function useTaskInput({ return createTask( { taskName: query.trim(), - issueType: taskIssue.current || undefined, + issueType: taskIssue.current || 'Bug', status: taskStatus.current || undefined, priority: taskPriority.current || undefined, size: taskSize.current || undefined, diff --git a/apps/web/app/hooks/features/useTeamTasks.ts b/apps/web/app/hooks/features/useTeamTasks.ts index 2b83ec20f..8097779ab 100644 --- a/apps/web/app/hooks/features/useTeamTasks.ts +++ b/apps/web/app/hooks/features/useTeamTasks.ts @@ -33,6 +33,7 @@ import { useQuery } from '../useQuery'; import { useSyncRef } from '../useSyncRef'; import { useOrganizationEmployeeTeams } from './useOrganizatioTeamsEmployee'; import { useAuthenticateUser } from './useAuthenticateUser'; +import { useTaskStatus } from './useTaskStatus'; export function useTeamTasks() { const { updateOrganizationTeamEmployeeActiveTask } = useOrganizationEmployeeTeams(); @@ -48,7 +49,7 @@ export function useTeamTasks() { const authUser = useSyncRef(useRecoilValue(userState)); const memberActiveTaskId = useRecoilValue(memberActiveTaskIdState); // const [employeeState, setEmployeeState] = useRecoilState(employeeTasksState); - + const { taskStatus } = useTaskStatus(); const activeTeam = useRecoilValue(activeTeamState); const activeTeamRef = useSyncRef(activeTeam); @@ -57,7 +58,7 @@ export function useTeamTasks() { const { firstLoad, firstLoadData: firstLoadTasksData } = useFirstLoad(); // Queries hooks - const { queryCall, loading, loadingRef, } = useQuery(getTeamTasksAPI); + const { queryCall, loading, loadingRef } = useQuery(getTeamTasksAPI); const { queryCall: getTasksByIdQueryCall, loading: getTasksByIdLoading } = useQuery(getTasksByIdAPI); const { queryCall: getTasksByEmployeeIdQueryCall, loading: getTasksByEmployeeIdLoading } = useQuery(getTasksByEmployeeIdAPI); @@ -214,7 +215,7 @@ export function useTeamTasks() { { taskName, issueType, - status, + status = taskStatus[0]?.name, priority, size, tags, @@ -230,11 +231,13 @@ export function useTeamTasks() { }, members?: { id: string }[] ) => { + const activeStatus = taskStatus.find((ts) => ts.name == status); return createQueryCall( { title: taskName, issueType, status, + taskStatusId: activeStatus?.id, priority, size, tags, diff --git a/apps/web/app/hooks/useInfinityFetch.ts b/apps/web/app/hooks/useInfinityFetch.ts index bf56e8374..99bd60f7b 100644 --- a/apps/web/app/hooks/useInfinityFetch.ts +++ b/apps/web/app/hooks/useInfinityFetch.ts @@ -2,30 +2,34 @@ import React from 'react'; -export const getPartData = ({ offset = 0, limit = 10, arr = [] }: { offset?: number; limit?: number; arr: any[] }) => - arr.slice(0, offset * limit + limit); +export const getPartData = ({ offset = 0, limit = 10, arr = [] }: { offset?: number; limit?: number; arr: any[] }) => { + const startIndex = offset * limit; + if (startIndex > arr.length) return arr; + return arr.slice(startIndex, Math.min(startIndex + limit, arr.length)); +}; export const useInfinityScrolling = (arr: T[], lim?: number) => { const limit = lim ?? 10; - const [offset, setOffset] = React.useState(0); - const [data, setData] = React.useState(arr); + const [offset, setOffset] = React.useState(1); + const [data, setData] = React.useState([]); const getSomeTasks = React.useCallback( (offset: number) => { - setData(getPartData({ arr, limit, offset })); + setData(() => { + const newData = getPartData({ arr, limit, offset }); + return newData; + }); }, [arr, limit] ); const nextOffset = React.useCallback(() => { setOffset((prev) => prev + 1); - setData((prev) => getPartData({ arr: prev, limit, offset })); - }, [limit, offset]); + }, []); React.useEffect(() => { getSomeTasks(offset); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [offset]); + }, [getSomeTasks, offset]); return { offset, diff --git a/apps/web/app/interfaces/ITask.ts b/apps/web/app/interfaces/ITask.ts index 6f28b51f0..3c7091549 100644 --- a/apps/web/app/interfaces/ITask.ts +++ b/apps/web/app/interfaces/ITask.ts @@ -20,6 +20,7 @@ export type ITeamTask = { startDate?: string | null; projectId: string; public: boolean; + taskStatusId?: string; resolvedAt?: string; creatorId: string; members: IEmployee[]; @@ -149,6 +150,7 @@ export interface ICreateTask { status?: string; size?: string; priority?: string; + taskStatusId?: string; issueType?: string; members?: { id: string; [x: string]: any }[]; estimateDays?: number; diff --git a/apps/web/app/services/client/api/tasks.ts b/apps/web/app/services/client/api/tasks.ts index e9a524197..5e34439f0 100644 --- a/apps/web/app/services/client/api/tasks.ts +++ b/apps/web/app/services/client/api/tasks.ts @@ -114,12 +114,10 @@ export async function createTeamTaskAPI(body: Partial & { title: st const teamId = getActiveTeamIdCookie(); const tenantId = getTenantIdCookie(); const projectId = getActiveProjectIdCookie(); - const title = body.title.trim() || ''; const datas: ICreateTask = { description: '', - status: 'open', members: user?.employee?.id ? [{ id: user.employee.id }] : [], teams: [ { diff --git a/apps/web/lib/components/Kanban.tsx b/apps/web/lib/components/Kanban.tsx index b7f2ab8e1..db0f3e3ac 100644 --- a/apps/web/lib/components/Kanban.tsx +++ b/apps/web/lib/components/Kanban.tsx @@ -18,11 +18,11 @@ import { Popover, PopoverContent, PopoverTrigger } from '@components/ui/popover' import { Button } from '@components/ui/button'; import { useTranslations } from 'next-intl'; import { AddIcon, ChevronLeftIcon } from 'assets/svg'; -import Skeleton from 'react-loading-skeleton'; import { useModal } from '@app/hooks'; import { Modal } from './modal'; import CreateTaskModal from '@components/pages/kanban/create-task-modal'; +import Image from 'next/image'; const grid = 8; @@ -64,9 +64,12 @@ function headerStyleChanger(snapshot: DraggableStateSnapshot, bgColor: any) { * @returns */ function InnerItemList({ items, title }: { title: string; items: ITeamTask[]; dropSnapshot: DroppableStateSnapshot }) { + const t = useTranslations(); + const { isOpen, closeModal, openModal } = useModal(); + return ( <> -
+
{items.map((item: ITeamTask, index: number) => ( {(dragProvided: DraggableProvided, dragSnapshot: DraggableStateSnapshot) => ( @@ -89,6 +92,23 @@ function InnerItemList({ items, title }: { title: string; items: ITeamTask[]; dr )} ))} + {items.length == 0 && ( +
+
+ not found! +
+
+ +

{t('common.CREATE_TASK')}

+
+
+ )} + + +
); @@ -137,28 +157,18 @@ export const KanbanDroppable = ({ }) => { return ( <> - {content.length > 0 ? ( - - {(dropProvided: DroppableProvided, dropSnapshot: DroppableStateSnapshot) => ( -
- -
- )} -
- ) : ( -
- {isLoading ? ( - - ) : ( - 'not found!' - )} -
- )} + + {(dropProvided: DroppableProvided, dropSnapshot: DroppableStateSnapshot) => ( +
+ +
+ )} +
); }; @@ -193,6 +203,8 @@ export const EmptyKanbanDroppable = ({ }; }, []); + const { isOpen, closeModal, openModal } = useModal(); + if (!enabled) return null; return ( @@ -235,14 +247,18 @@ export const EmptyKanbanDroppable = ({ align="start" className="md:p-1 rounded-x dark:bg-[#1B1D22] dark:border-[0.125rem] border-[#0000001A] dark:border-[#26272C] w-40" > - {['Delete', 'Archive', 'Copy'].map((v) => ( -

- {v} -

- ))} +
openModal()} + > + Create Task +
+
toggleColumn(title, false)} + > + Collapse Column +
@@ -273,19 +289,26 @@ export const EmptyKanbanDroppable = ({ )} )} + + + ); }; const KanbanDraggableHeader = ({ title, + icon, items, snapshot, + createTask, provided, backgroundColor }: { title: string; items: any; + icon: string; + createTask: () => void; snapshot: DraggableStateSnapshot; backgroundColor: string; provided: DraggableProvided; @@ -299,6 +322,7 @@ const KanbanDraggableHeader = ({ style={headerStyleChanger(snapshot, backgroundColor)} >
+ {title}

- {['Delete', 'Archive', 'Copy'].map((v) => ( -

- {v} -

- ))} +
createTask()} + > + Create Task +
+
toggleColumn(title, true)} + > + Collapse Column +
+ {/*
toggleColumn(title, true)} + > + Edit Status +
*/}

diff --git a/apps/web/lib/components/kanban-card.tsx b/apps/web/lib/components/kanban-card.tsx index bbbe27edb..cfab76262 100644 --- a/apps/web/lib/components/kanban-card.tsx +++ b/apps/web/lib/components/kanban-card.tsx @@ -191,15 +191,18 @@ export default function Item(props: ItemProps) { <>
- - - + {item.issueType && ( + + + + - + )} #{item.number} {item.title} diff --git a/apps/web/lib/components/pagination.tsx b/apps/web/lib/components/pagination.tsx index 35d173f0c..4960bf91d 100644 --- a/apps/web/lib/components/pagination.tsx +++ b/apps/web/lib/components/pagination.tsx @@ -23,7 +23,7 @@ export function Paginate({ total, itemsPerPage = 10, onPageChange, itemOffset, e +
{t('common.NEXT')} +
{t('common.PREV')} { const { isOpen, closeModal, openModal } = useModal(); return ( -
+

{startedAt} - {stoppedAt}

diff --git a/apps/web/lib/features/activity/components/screenshot-item.tsx b/apps/web/lib/features/activity/components/screenshot-item.tsx index 265bb2859..64657bf62 100644 --- a/apps/web/lib/features/activity/components/screenshot-item.tsx +++ b/apps/web/lib/features/activity/components/screenshot-item.tsx @@ -24,7 +24,7 @@ const ScreenshotItem = ({ return (
-
+
{showProgress ? ( <>

diff --git a/apps/web/lib/features/task/task-all-status-type.tsx b/apps/web/lib/features/task/task-all-status-type.tsx index 09803122f..26c67f1a3 100644 --- a/apps/web/lib/features/task/task-all-status-type.tsx +++ b/apps/web/lib/features/task/task-all-status-type.tsx @@ -56,7 +56,7 @@ export function TaskAllStatusTypes({ return (
-
+
{showStatus && task?.status && taskStatus[task?.status] && ( = { Bug: { - icon: , + icon: , name: 'Bug', bgColor: '#923535' }, Task: { - icon: , + icon: , name: 'Task', bgColor: '#5483BA' }, Story: { - icon: , + icon: , name: 'Story', bgColor: '#66BB97' }, Epic: { - icon: , + icon: , name: 'Custom', bgColor: '#8154BA' } diff --git a/apps/web/lib/features/team-member-cell.tsx b/apps/web/lib/features/team-member-cell.tsx index 4cf7f4f58..1476c38ec 100644 --- a/apps/web/lib/features/team-member-cell.tsx +++ b/apps/web/lib/features/team-member-cell.tsx @@ -9,18 +9,24 @@ import { UserInfo } from './team/user-team-card/user-info'; import { UserTeamCardMenu } from './team/user-team-card/user-team-card-menu'; import React from 'react'; import get from 'lodash/get'; +import { useRecoilValue } from 'recoil'; +import { fullWidthState } from '@app/stores/fullWidth'; export function TaskCell({ row }: { row: any }) { const member = row.original as OT_Member; const memberInfo = useTeamMemberCard(member); const taskEdition = useTMCardTaskEdit(memberInfo.memberTask); const publicTeam = false; + const fullWidth = useRecoilValue(fullWidthState); return ( ); @@ -38,6 +44,7 @@ export function UserInfoCell({ cell }: { cell: any }) { export function WorkedOnTaskCell({ row }: { row: any }) { const member = row.original as OT_Member; const memberInfo = useTeamMemberCard(member); + const fullWidth = useRecoilValue(fullWidthState); return ( ); } @@ -60,7 +70,9 @@ export function TaskEstimateInfoCell({ row }: { row: any }) { memberInfo={memberInfo} edition={taskEdition} activeAuthTask={true} - className="flex flex-col justify-center " + className={clsxm( + 'flex flex-col justify-center items-center 2xl:w-[7rem] 3xl:w-[10rem]' + )} /> ); } diff --git a/apps/web/lib/features/team-members-kanban-view.tsx b/apps/web/lib/features/team-members-kanban-view.tsx index 15855df46..f17aa6de4 100644 --- a/apps/web/lib/features/team-members-kanban-view.tsx +++ b/apps/web/lib/features/team-members-kanban-view.tsx @@ -1,5 +1,6 @@ +import { useTaskStatus } from '@app/hooks'; import { useKanban } from '@app/hooks/features/useKanban'; -import { ITaskStatus, ITaskStatusItemList, ITeamTask } from '@app/interfaces'; +import { ITaskStatusItemList, ITeamTask } from '@app/interfaces'; import { IKanban } from '@app/interfaces/IKanban'; import { clsxm } from '@app/utils'; import KanbanDraggable, { EmptyKanbanDroppable } from 'lib/components/Kanban'; @@ -24,13 +25,21 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: reorderStatus, addNewTask } = useKanban(); - const [columns, setColumn] = useState(Object.keys(kanbanBoardTasks)); + + const [columns, setColumn] = useState( + Object.keys(kanbanBoardTasks).map((key) => { + const columnInfo = kanbanColumns.find((item) => item.name === key); + return { name: key, icon: columnInfo ? columnInfo.fullIconUrl : '' }; + }) + ); + const { taskStatus: ts } = useTaskStatus(); const reorderTask = (list: ITeamTask[], startIndex: number, endIndex: number) => { const tasks = Array.from(list); const [removedTask] = tasks.splice(startIndex, 1); tasks.splice(endIndex, 0, removedTask); return tasks; }; + const reorderKanbanTasks = ({ kanbanTasks, source, @@ -48,7 +57,7 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: const nextTaskStatus = [...kanbanTasks[destinationDroppableID]]; const targetStatus = currentTaskStatus[source.index]; - // moving to same list + // Moving to the same list if (sourceDroppableID === destinationDroppableID) { const reorderedKanbanTasks = reorderTask(currentTaskStatus, sourceIndex, destinationIndex); const result = { @@ -60,14 +69,18 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: }; } - // remove from original + // Remove from original currentTaskStatus.splice(sourceIndex, 1); - const taskstatus = destinationDroppableID as ITaskStatus; - - const updateTaskStatusData = { ...targetStatus, status: taskstatus }; + const taskstatus = destinationDroppableID as any; + + const updateTaskStatusData = { + ...targetStatus, + status: taskstatus, + taskStatusId: ts.find((v) => v.name?.toLowerCase() == taskstatus.toLowerCase())?.id + }; - // update task status on server + // update task status on the server updateTaskStatus(updateTaskStatusData); // insert into next @@ -109,6 +122,7 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: const onDragEnd = (result: DropResult) => { if (result.combine) { if (result.type === 'COLUMN') { + console.log('re-order-column'); const shallow = [...columns]; shallow.splice(result.source.index, 1); setColumn(shallow); @@ -116,6 +130,7 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: } const item = items[result.source.droppableId]; + const withItemRemoved = [...item]; withItemRemoved.splice(result.source.index, 1); @@ -124,11 +139,11 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: ...items, [result.source.droppableId]: withItemRemoved }; + updateKanbanBoard(orderedItems); return; } - // dropped nowhere if (!result.destination) { return; @@ -144,7 +159,8 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: if (result.type === 'COLUMN') { const reorderedItem = reorderColumn(columns, source.index, destination.index); - //update column order in server side + + // Update column order on the server side reorderedItem.map((item: string, index: number) => { return reorderStatus(item, index); }); @@ -174,10 +190,10 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: }; }, []); - if (!enabled) return null; + if (!enabled) return null; // ['open','close'] + return ( - <> - {/*
*/} + <> {columns.length > 0 && ( @@ -193,15 +209,15 @@ export const KanbanView = ({ kanbanBoardTasks, isLoading }: { kanbanBoardTasks: > {columns.length > 0 ? ( <> - {columns.map((column: string, index: number) => { + {columns.map((column: any, index: number) => { return (
- {isColumnCollapse(column) ? ( + {isColumnCollapse(column.name) ? ( diff --git a/apps/web/lib/features/team/user-team-card/index.tsx b/apps/web/lib/features/team/user-team-card/index.tsx index bc9685060..1b631a1dd 100644 --- a/apps/web/lib/features/team/user-team-card/index.tsx +++ b/apps/web/lib/features/team/user-team-card/index.tsx @@ -1,7 +1,14 @@ 'use client'; import { secondsToTime } from '@app/helpers'; -import { useCollaborative, useTMCardTaskEdit, useTaskStatistics, useTeamMemberCard } from '@app/hooks'; +import { + useCollaborative, + useTMCardTaskEdit, + useTaskStatistics, + useOrganizationTeams, + useAuthenticateUser, + useTeamMemberCard +} from '@app/hooks'; import { IClassName, IOrganizationTeamList, OT_Member } from '@app/interfaces'; import { timerSecondsState } from '@app/stores'; import { clsxm } from '@app/utils'; @@ -53,6 +60,10 @@ export function UserTeamCard({ const setActivityFilter = useSetRecoilState(activityTypeState); const { activeTaskTotalStat, addSeconds } = useTaskStatistics(seconds); const [showActivity, setShowActivity] = React.useState(false); + const { activeTeamManagers } = useOrganizationTeams(); + const { user } = useAuthenticateUser(); + + const isManagerConnectedUser = activeTeamManagers.findIndex((member) => member.employee?.user?.id == user?.id); const showActivityFilter = (type: 'DATE' | 'TICKET', member: OT_Member | null) => { setShowActivity((prev) => !prev); @@ -138,16 +149,18 @@ export function UserTeamCard({ className="flex-1 lg:px-4 px-2 overflow-y-hidden" publicTeam={publicTeam} /> -

showActivityFilter('TICKET', memberInfo.member ?? null)} - > - {!showActivity ? ( - - ) : ( - - )} -

+ {isManagerConnectedUser != 1 ? ( +

showActivityFilter('TICKET', memberInfo.member ?? null)} + > + {!showActivity ? ( + + ) : ( + + )} +

+ ) : null}
@@ -173,16 +186,18 @@ export function UserTeamCard({ {/* TodayWorkedTime */}
-

showActivityFilter('DATE', memberInfo.member ?? null)} - className="flex items-center w-8 h-8 border dark:border-gray-800 rounded justify-center cursor-pointer text-center" - > - {!showActivity ? ( - - ) : ( - - )} -

+ {isManagerConnectedUser != -1 ? ( +

showActivityFilter('DATE', memberInfo.member ?? null)} + className="flex items-center w-8 h-8 border dark:border-gray-800 rounded justify-center cursor-pointer text-center" + > + {!showActivity ? ( + + ) : ( + + )} +

+ ) : null}
{/* Card menu */}
{menu}
diff --git a/apps/web/lib/features/team/user-team-card/task-info.tsx b/apps/web/lib/features/team/user-team-card/task-info.tsx index 0c96e6194..627409551 100644 --- a/apps/web/lib/features/team/user-team-card/task-info.tsx +++ b/apps/web/lib/features/team/user-team-card/task-info.tsx @@ -14,12 +14,17 @@ export function TaskInfo({ className, memberInfo, edition, publicTeam }: Props) return (
{/* task */} -
+
{edition.task && ( )} diff --git a/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx b/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx index ea335a62b..0627568c9 100644 --- a/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx +++ b/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx @@ -27,11 +27,12 @@ const UserTeamActivity = ({ showActivity, member }: { showActivity: boolean; mem leave="transition-opacity duration-150" leaveFrom="opacity-100" leaveTo="opacity-0" + className="w-full" > -
+

Activity for Today

-
+
{t('timer.TIME_ACTIVITY')} @@ -41,7 +42,7 @@ const UserTeamActivity = ({ showActivity, member }: { showActivity: boolean; mem
-
+
{Object.values(ActivityFilters).map((filter: string) => ( @@ -62,7 +63,7 @@ const UserTeamActivity = ({ showActivity, member }: { showActivity: boolean; mem ))} - + diff --git a/apps/web/lib/features/user-profile-tasks.tsx b/apps/web/lib/features/user-profile-tasks.tsx index 538254942..1e46c4d38 100644 --- a/apps/web/lib/features/user-profile-tasks.tsx +++ b/apps/web/lib/features/user-profile-tasks.tsx @@ -31,7 +31,7 @@ export function UserProfileTask({ profile, tabFiltered }: Props) { profile.member?.running == true ? t.id !== profile.activeUserTeamTask?.id : t ); const { nextOffset, data } = useInfinityScrolling(otherTasks); - const dataToDisplay = otherTasks.length < 10 ? otherTasks : data; + // const data = otherTasks.length < 10 ? otherTasks : data; // const { total, onPageChange, itemsPerPage, itemOffset, endOffset, setItemsPerPage, currentItems } = // usePagination(otherTasks); @@ -86,7 +86,7 @@ export function UserProfileTask({ profile, tabFiltered }: Props) { )}
    - {dataToDisplay.map((task, index) => { + {data.map((task, index) => { return (
  • diff --git a/yarn.lock b/yarn.lock index 1167c21a3..06fc7f4e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22253,9 +22253,9 @@ webidl-conversions@^3.0.0: integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== webpack-dev-middleware@^5.3.1: - version "5.3.3" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" - integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + version "5.3.4" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517" + integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== dependencies: colorette "^2.0.10" memfs "^3.4.3"