Merge pull request #226 from OminduHirushka/update/event-tracking

update event integrations
This commit is contained in:
Chamika J
2025-07-04 13:36:54 +05:30
committed by GitHub
15 changed files with 219 additions and 35 deletions

View File

@@ -23,12 +23,15 @@ import { fetchBoardTaskGroups } from '@/features/board/board-slice';
import { setImportTaskTemplateDrawerOpen } from '@/features/project/project.slice';
import useTabSearchParam from '@/hooks/useTabSearchParam';
import { fetchTaskGroups } from '@/features/tasks/tasks.slice';
import { evt_project_import_tasks } from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const ImportTaskTemplate = () => {
const dispatch = useAppDispatch();
const [form] = Form.useForm();
const { t } = useTranslation('project-view/import-task-templates');
const { tab } = useTabSearchParam();
const { trackMixpanelEvent } = useMixpanelTracking();
const { importTaskTemplateDrawerOpen, projectId } = useAppSelector(state => state.projectReducer);
const [templates, setTemplates] = useState<ITaskTemplatesGetResponse[]>([]);
@@ -86,6 +89,7 @@ const ImportTaskTemplate = () => {
if (!projectId || tasks.length === 0) return;
try {
trackMixpanelEvent(evt_project_import_tasks);
setImporting(true);
const res = await taskTemplatesApiService.importTemplate(projectId, tasks);
if (res.done) {
@@ -117,7 +121,12 @@ const ImportTaskTemplate = () => {
footer={
<Flex justify="end" gap={10}>
<Button onClick={handleClose}>{t('cancel')}</Button>
<Button type="primary" onClick={handleImport} loading={importing} disabled={tasks.length === 0}>
<Button
type="primary"
onClick={handleImport}
loading={importing}
disabled={tasks.length === 0}
>
{t('import')}
</Button>
</Flex>

View File

@@ -8,6 +8,8 @@ import logger from '@/utils/errorLogger';
import { ITaskTemplateGetResponse } from '@/types/settings/task-templates.types';
import { useAppSelector } from '@/hooks/useAppSelector';
import { setSelectedTasks } from '@/features/project/project.slice';
import { evt_project_task_create } from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
interface TaskTemplateDrawerProps {
showDrawer: boolean;
@@ -21,6 +23,7 @@ const TaskTemplateDrawer = ({
onClose,
}: TaskTemplateDrawerProps) => {
const dispatch = useAppDispatch();
const {trackMixpanelEvent} = useMixpanelTracking();
const { t } = useTranslation('task-template-drawer');
const [form] = Form.useForm();
const [templateData, setTemplateData] = useState<ITaskTemplateGetResponse>({});
@@ -75,6 +78,8 @@ const TaskTemplateDrawer = ({
const values = form.getFieldsValue();
if (!values.name || !templateData.tasks) return;
try {
trackMixpanelEvent(evt_project_task_create);
setCreatingTemplate(true);
const res = await taskTemplatesApiService.createTemplate({
name: values.name || '',

View File

@@ -6,6 +6,8 @@ import { useAppDispatch } from '@/hooks/useAppDispatch';
import { NewTaskType, updateTaskDate } from '@features/roadmap/roadmap-slice';
import { colors } from '@/styles/colors';
import RoadmapTaskCell from './roadmap-task-cell';
import { evt_roadmap_drag_change_date } from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const RoadmapTable = () => {
// Get task list and expanded tasks from roadmap slice
@@ -15,11 +17,18 @@ const RoadmapTable = () => {
const themeMode = useAppSelector(state => state.themeReducer.mode);
const dispatch = useAppDispatch();
const { trackMixpanelEvent } = useMixpanelTracking();
// function to handle date changes
const handleDateChange = (taskId: string, dateType: 'start' | 'end', date: Dayjs) => {
const updatedDate = date.toDate();
trackMixpanelEvent(evt_roadmap_drag_change_date, {
task_id: taskId,
date_type: dateType,
new_date: updatedDate.toISOString(),
});
dispatch(
updateTaskDate({
taskId,

View File

@@ -37,7 +37,7 @@ import logger from '@/utils/errorLogger';
// Components
import EmptyListPlaceholder from '../../../../components/EmptyListPlaceholder';
import { useAppSelector } from '@/hooks/useAppSelector';
import { evt_project_members_visit } from '@/shared/worklenz-analytics-events';
import { evt_project_members_visit, evt_people_delete } from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
interface PaginationType {
@@ -104,6 +104,11 @@ const ProjectViewMembers = () => {
try {
const res = await projectMembersApiService.deleteProjectMember(memberId, projectId);
if (res.done) {
trackMixpanelEvent(evt_people_delete, {
project_id: projectId,
member_id: memberId,
});
void getProjectMembers();
}
} catch (error) {
@@ -138,7 +143,14 @@ const ProjectViewMembers = () => {
// Effects
useEffect(() => {
void getProjectMembers();
}, [refreshTimestamp, projectId, pagination.current, pagination.pageSize, pagination.field, pagination.order]);
}, [
refreshTimestamp,
projectId,
pagination.current,
pagination.pageSize,
pagination.field,
pagination.order,
]);
useEffect(() => {
trackMixpanelEvent(evt_project_members_visit);
@@ -151,8 +163,12 @@ const ProjectViewMembers = () => {
title: t('nameColumn'),
dataIndex: 'name',
sorter: true,
sortOrder: pagination.order === 'ascend' && pagination.field === 'name' ? 'ascend' :
pagination.order === 'descend' && pagination.field === 'name' ? 'descend' : null,
sortOrder:
pagination.order === 'ascend' && pagination.field === 'name'
? 'ascend'
: pagination.order === 'descend' && pagination.field === 'name'
? 'descend'
: null,
render: (_, record: IProjectMemberViewModel) => (
<Flex gap={8} align="center">
<Avatar size={28} src={record.avatar_url}>
@@ -167,8 +183,12 @@ const ProjectViewMembers = () => {
title: t('jobTitleColumn'),
dataIndex: 'job_title',
sorter: true,
sortOrder: pagination.order === 'ascend' && pagination.field === 'job_title' ? 'ascend' :
pagination.order === 'descend' && pagination.field === 'job_title' ? 'descend' : null,
sortOrder:
pagination.order === 'ascend' && pagination.field === 'job_title'
? 'ascend'
: pagination.order === 'descend' && pagination.field === 'job_title'
? 'descend'
: null,
render: (_, record: IProjectMemberViewModel) => (
<Typography.Text style={{ marginInlineStart: 12 }}>
{record?.job_title || '-'}
@@ -180,8 +200,12 @@ const ProjectViewMembers = () => {
title: t('emailColumn'),
dataIndex: 'email',
sorter: true,
sortOrder: pagination.order === 'ascend' && pagination.field === 'email' ? 'ascend' :
pagination.order === 'descend' && pagination.field === 'email' ? 'descend' : null,
sortOrder:
pagination.order === 'ascend' && pagination.field === 'email'
? 'ascend'
: pagination.order === 'descend' && pagination.field === 'email'
? 'descend'
: null,
render: (_, record: IProjectMemberViewModel) => (
<Typography.Text>{record.email}</Typography.Text>
),
@@ -210,8 +234,12 @@ const ProjectViewMembers = () => {
title: t('accessColumn'),
dataIndex: 'access',
sorter: true,
sortOrder: pagination.order === 'ascend' && pagination.field === 'access' ? 'ascend' :
pagination.order === 'descend' && pagination.field === 'access' ? 'descend' : null,
sortOrder:
pagination.order === 'ascend' && pagination.field === 'access'
? 'ascend'
: pagination.order === 'descend' && pagination.field === 'access'
? 'descend'
: null,
render: (_, record: IProjectMemberViewModel) => (
<Typography.Text style={{ textTransform: 'capitalize' }}>{record.access}</Typography.Text>
),

View File

@@ -22,8 +22,17 @@ import { useAppSelector } from '@/hooks/useAppSelector';
import { SocketEvents } from '@/shared/socket-events';
import { useAuthService } from '@/hooks/useAuth';
import { useSocket } from '@/socket/socketContext';
import { setProject, setImportTaskTemplateDrawerOpen, setRefreshTimestamp } from '@features/project/project.slice';
import { addTask, fetchTaskGroups, fetchTaskListColumns, IGroupBy } from '@features/tasks/tasks.slice';
import {
setProject,
setImportTaskTemplateDrawerOpen,
setRefreshTimestamp,
} from '@features/project/project.slice';
import {
addTask,
fetchTaskGroups,
fetchTaskListColumns,
IGroupBy,
} from '@features/tasks/tasks.slice';
import ProjectStatusIcon from '@/components/common/project-status-icon/project-status-icon';
import { formatDate } from '@/utils/timeUtils';
import { toggleSaveAsTemplateDrawer } from '@/features/projects/projectsSlice';
@@ -49,6 +58,14 @@ import useTabSearchParam from '@/hooks/useTabSearchParam';
import { addTaskCardToTheTop, fetchBoardTaskGroups } from '@/features/board/board-slice';
import { fetchPhasesByProjectId } from '@/features/projects/singleProject/phase/phases.slice';
import {
evt_project_task_create,
evt_project_refresh_click,
evt_project_settings_click,
evt_project_import_tasks_click,
} from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const ProjectViewHeader = () => {
const navigate = useNavigate();
const { t } = useTranslation('project-view/project-view-header');
@@ -56,24 +73,29 @@ const ProjectViewHeader = () => {
const currentSession = useAuthService().getCurrentSession();
const isOwnerOrAdmin = useAuthService().isOwnerOrAdmin();
const isProjectManager = useIsProjectManager();
const { trackMixpanelEvent } = useMixpanelTracking();
const { tab } = useTabSearchParam();
const { socket } = useSocket();
const {
project: selectedProject,
projectId,
} = useAppSelector(state => state.projectReducer);
const { project: selectedProject, projectId } = useAppSelector(state => state.projectReducer);
const { loadingGroups, groupBy } = useAppSelector(state => state.taskReducer);
const [creatingTask, setCreatingTask] = useState(false);
const handleRefresh = () => {
if (!projectId) return;
trackMixpanelEvent(evt_project_refresh_click, {
project_id: projectId,
tab: tab,
project_name: selectedProject?.name,
});
switch (tab) {
case 'tasks-list':
dispatch(fetchTaskListColumns(projectId));
dispatch(fetchPhasesByProjectId(projectId))
dispatch(fetchPhasesByProjectId(projectId));
dispatch(fetchTaskGroups(projectId));
break;
case 'board':
@@ -113,6 +135,11 @@ const ProjectViewHeader = () => {
const handleSettingsClick = () => {
if (selectedProject?.id) {
trackMixpanelEvent(evt_project_settings_click, {
project_id: selectedProject.id,
project_name: selectedProject.name,
});
dispatch(setProjectId(selectedProject.id));
dispatch(fetchProjectData(selectedProject.id));
dispatch(toggleProjectDrawer());
@@ -123,6 +150,14 @@ const ProjectViewHeader = () => {
try {
setCreatingTask(true);
trackMixpanelEvent(evt_project_task_create, {
project_id: selectedProject?.id,
project_name: selectedProject?.name,
reporter_id: currentSession?.id,
team_id: currentSession?.team_id,
creation_method: 'quick_create',
});
const body: ITaskCreateRequest = {
name: DEFAULT_TASK_NAME,
project_id: selectedProject?.id,
@@ -155,6 +190,11 @@ const ProjectViewHeader = () => {
};
const handleImportTaskTemplate = () => {
trackMixpanelEvent(evt_project_import_tasks_click, {
project_id: selectedProject?.id,
project_name: selectedProject?.name,
});
dispatch(setImportTaskTemplateDrawerOpen(true));
};
@@ -221,7 +261,7 @@ const ProjectViewHeader = () => {
/>
</Tooltip>
{(isOwnerOrAdmin) && (
{isOwnerOrAdmin && (
<Tooltip title="Save as template">
<Button
shape="circle"
@@ -301,7 +341,6 @@ const ProjectViewHeader = () => {
{createPortal(<ProjectDrawer onClose={() => {}} />, document.body, 'project-drawer')}
{createPortal(<ImportTaskTemplate />, document.body, 'import-task-template')}
{createPortal(<SaveProjectAsTemplate />, document.body, 'save-project-as-template')}
</>
);
};

View File

@@ -12,11 +12,14 @@ import { fetchStatusesCategories } from '@/features/taskAttributes/taskStatusSli
import { fetchPhasesByProjectId } from '@/features/projects/singleProject/phase/phases.slice';
import { Empty } from 'antd';
import useTabSearchParam from '@/hooks/useTabSearchParam';
import { evt_project_task_list_visit } from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const ProjectViewTaskList = () => {
const dispatch = useAppDispatch();
const { projectView } = useTabSearchParam();
const [searchParams, setSearchParams] = useSearchParams();
const { trackMixpanelEvent } = useMixpanelTracking();
const { projectId } = useAppSelector(state => state.projectReducer);
const { taskGroups, loadingGroups, groupBy, archived, fields, search } = useAppSelector(
@@ -38,6 +41,8 @@ const ProjectViewTaskList = () => {
}, [projectView, searchParams, setSearchParams]);
useEffect(() => {
trackMixpanelEvent(evt_project_task_list_visit);
if (projectId && groupBy) {
if (!loadingColumns) dispatch(fetchTaskListColumns(projectId));
if (!loadingPhases) dispatch(fetchPhasesByProjectId(projectId));
@@ -54,10 +59,10 @@ const ProjectViewTaskList = () => {
<Flex vertical gap={16} style={{ overflowX: 'hidden' }}>
<TaskListFilters position="list" />
{(taskGroups.length === 0 && !loadingGroups) ? (
{taskGroups.length === 0 && !loadingGroups ? (
<Empty description="No tasks group found" />
) : (
<Skeleton active loading={loadingGroups} className='mt-4 p-4'>
<Skeleton active loading={loadingGroups} className="mt-4 p-4">
<TaskGroupWrapper taskGroups={taskGroups} groupBy={groupBy} />
</Skeleton>
)}

View File

@@ -1,5 +1,5 @@
import { Button, DatePicker, DatePickerProps, Flex, Select, Space } from 'antd';
import React, { useRef, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { SettingOutlined } from '@ant-design/icons';
import { useDispatch } from 'react-redux';
import { setDate, setType, toggleSettingsDrawer } from '@/features/schedule/scheduleSlice';
@@ -11,6 +11,8 @@ import ScheduleDrawer from '@/features/schedule/ScheduleDrawer';
import GranttChart from '@/components/schedule/grant-chart/grantt-chart';
import { useAppSelector } from '@/hooks/useAppSelector';
import { PickerType } from '@/types/schedule/schedule-v2.types';
import { evt_schedule_page_visit } from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const { Option } = Select;
@@ -31,6 +33,7 @@ const Schedule: React.FC = () => {
const dispatch = useDispatch();
const granttChartRef = useRef<any>(null);
const { date, type } = useAppSelector(state => state.scheduleReducer);
const { trackMixpanelEvent } = useMixpanelTracking();
useDocumentTitle('Schedule');
@@ -53,6 +56,10 @@ const Schedule: React.FC = () => {
console.log('Today:', today);
};
useEffect(() => {
trackMixpanelEvent(evt_schedule_page_visit);
}, []);
return (
<div style={{ marginBlockStart: 65, minHeight: '90vh' }}>
<Flex align="center" justify="space-between">

View File

@@ -20,6 +20,11 @@ import { categoriesApiService } from '@/api/settings/categories/categories.api.s
import { IProjectCategory, IProjectCategoryViewModel } from '@/types/project/projectCategory.types';
import { useDocumentTitle } from '@/hooks/useDoumentTItle';
import { useAppDispatch } from '@/hooks/useAppDispatch';
import {
evt_settings_categories_visit,
evt_settings_category_delete,
} from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const CategoriesSettings = () => {
// localization
@@ -28,6 +33,7 @@ const CategoriesSettings = () => {
useDocumentTitle('Manage Categories');
const dispatch = useAppDispatch();
const { trackMixpanelEvent } = useMixpanelTracking();
// get currently hover row
const [hoverRow, setHoverRow] = useState<string | null>(null);
const [categories, setCategories] = useState<IProjectCategoryViewModel[]>([]);
@@ -56,6 +62,10 @@ const CategoriesSettings = () => {
};
}, []);
useEffect(() => {
trackMixpanelEvent(evt_settings_categories_visit);
}, [trackMixpanelEvent]);
useEffect(() => {
getCategories();
}, [getCategories]);
@@ -70,7 +80,9 @@ const CategoriesSettings = () => {
{
key: 'associatedTask',
title: t('associatedTaskColumn'),
render: (record: IProjectCategoryViewModel) => <Typography.Text>{record.usage}</Typography.Text>,
render: (record: IProjectCategoryViewModel) => (
<Typography.Text>{record.usage}</Typography.Text>
),
},
{
key: 'actionBtns',
@@ -82,7 +94,10 @@ const CategoriesSettings = () => {
icon={<ExclamationCircleFilled style={{ color: colors.vibrantOrange }} />}
okText={t('deleteConfirmationOk')}
cancelText={t('deleteConfirmationCancel')}
onConfirm={() => record.id && dispatch(deleteCategory(record.id))}
onConfirm={() => {
trackMixpanelEvent(evt_settings_category_delete, { categoryId: record.id });
record.id && dispatch(deleteCategory(record.id));
}}
>
<Tooltip title="Delete">
<Button shape="default" icon={<DeleteOutlined />} size="small" />

View File

@@ -31,11 +31,14 @@ import { DEFAULT_PAGE_SIZE } from '@/shared/constants';
import ClientDrawer from './client-drawer';
import { useDocumentTitle } from '@/hooks/useDoumentTItle';
import logger from '@/utils/errorLogger';
import { evt_settings_clients_visit, evt_settings_clients_create } from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const ClientsSettings: React.FC = () => {
const { t } = useTranslation('settings/clients');
const { clients } = useAppSelector(state => state.clientReducer);
const dispatch = useAppDispatch();
const { trackMixpanelEvent } = useMixpanelTracking();
useDocumentTitle('Manage Clients');
@@ -62,6 +65,10 @@ const ClientsSettings: React.FC = () => {
};
}, [pagination, searchQuery, dispatch]);
useEffect(() => {
trackMixpanelEvent(evt_settings_clients_visit);
}, [trackMixpanelEvent]);
useEffect(() => {
getClients();
}, [searchQuery]);

View File

@@ -27,6 +27,11 @@ import { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import JobTitleDrawer from './job-titles-drawer';
import logger from '@/utils/errorLogger';
import {
evt_settings_job_titles_visit,
evt_settings_job_titles_create,
} from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
interface PaginationType {
current: number;
@@ -42,6 +47,7 @@ const JobTitlesSettings = () => {
const { t } = useTranslation('settings/job-titles');
const dispatch = useAppDispatch();
useDocumentTitle('Manage Job Titles');
const { trackMixpanelEvent } = useMixpanelTracking();
const [selectedJobId, setSelectedJobId] = useState<string | null>(null);
const [showDrawer, setShowDrawer] = useState(false);
@@ -73,6 +79,10 @@ const JobTitlesSettings = () => {
};
}, [pagination.current, pagination.pageSize, pagination.field, pagination.order, searchQuery]);
useEffect(() => {
trackMixpanelEvent(evt_settings_job_titles_visit);
}, [trackMixpanelEvent]);
useEffect(() => {
getJobTitles();
}, [getJobTitles]);
@@ -83,6 +93,8 @@ const JobTitlesSettings = () => {
};
const handleCreateClick = () => {
trackMixpanelEvent(evt_settings_job_titles_create);
setSelectedJobId(null);
setShowDrawer(true);
};

View File

@@ -19,6 +19,11 @@ import { labelsApiService } from '@/api/taskAttributes/labels/labels.api.service
import CustomColorLabel from '@components/task-list-common/labelsSelector/custom-color-label';
import { useDocumentTitle } from '@/hooks/useDoumentTItle';
import logger from '@/utils/errorLogger';
import {
evt_settings_labels_visit,
evt_settings_labels_delete,
} from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const LabelsSettings = () => {
const { t } = useTranslation('settings/labels');
@@ -27,6 +32,7 @@ const LabelsSettings = () => {
const [searchQuery, setSearchQuery] = useState('');
const [labels, setLabels] = useState<ITaskLabel[]>([]);
const [loading, setLoading] = useState(false);
const { trackMixpanelEvent } = useMixpanelTracking();
const filteredData = useMemo(
() =>
@@ -49,12 +55,18 @@ const LabelsSettings = () => {
};
}, []);
useEffect(() => {
trackMixpanelEvent(evt_settings_labels_visit);
}, [trackMixpanelEvent]);
useEffect(() => {
getLabels();
}, [getLabels]);
const deleteLabel = async (id: string) => {
try {
trackMixpanelEvent(evt_settings_labels_delete, { labelId: id });
const response = await labelsApiService.deleteById(id);
if (response.done) {
getLabels();

View File

@@ -6,17 +6,24 @@ import { useDocumentTitle } from '@/hooks/useDoumentTItle';
import { INotificationSettings } from '@/types/settings/notifications.types';
import { profileSettingsApiService } from '@/api/settings/profile/profile-settings.api.service';
import logger from '@/utils/errorLogger';
import { evt_settings_notifications_visit } from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const NotificationsSettings = () => {
const { t } = useTranslation('settings/notifications');
const [form] = Form.useForm();
const themeMode = useAppSelector(state => state.themeReducer.mode);
const { trackMixpanelEvent } = useMixpanelTracking();
const [notificationsSettings, setNotificationsSettings] = useState<INotificationSettings>({});
const [isLoading, setIsLoading] = useState(false);
useDocumentTitle(t('title'));
useEffect(() => {
trackMixpanelEvent(evt_settings_notifications_visit);
}, [trackMixpanelEvent]);
const fetchNotificationsSettings = async () => {
try {
setIsLoading(true);

View File

@@ -11,10 +11,16 @@ import { ITaskTemplatesGetResponse } from '@/types/settings/task-templates.types
import logger from '@/utils/errorLogger';
import { taskTemplatesApiService } from '@/api/task-templates/task-templates.api.service';
import { calculateTimeGap } from '@/utils/calculate-time-gap';
import {
evt_settings_task_templates_visit,
evt_settings_task_templates_delete,
} from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const TaskTemplatesSettings = () => {
const { t } = useTranslation('settings/task-templates');
const dispatch = useAppDispatch();
const { trackMixpanelEvent } = useMixpanelTracking();
const themeMode = useAppSelector(state => state.themeReducer.mode);
const [taskTemplates, setTaskTemplates] = useState<ITaskTemplatesGetResponse[]>([]);
const [isLoading, setIsLoading] = useState(false);
@@ -34,12 +40,18 @@ const TaskTemplatesSettings = () => {
}
};
useEffect(() => {
trackMixpanelEvent(evt_settings_task_templates_visit);
}, [trackMixpanelEvent]);
useEffect(() => {
fetchTaskTemplates();
}, []);
const handleDeleteTemplate = async (id: string) => {
try {
trackMixpanelEvent(evt_settings_task_templates_delete, { templateId: id });
setIsLoading(true);
await taskTemplatesApiService.deleteTemplate(id);
await fetchTaskTemplates();
@@ -114,7 +126,7 @@ const TaskTemplatesSettings = () => {
pagination={{
size: 'small',
showSizeChanger: true,
showTotal: (total) => t('totalItems', { total })
showTotal: total => t('totalItems', { total }),
}}
columns={columns}
dataSource={taskTemplates}

View File

@@ -37,11 +37,15 @@ import { DEFAULT_PAGE_SIZE, PAGE_SIZE_OPTIONS } from '@/shared/constants';
import { teamMembersApiService } from '@/api/team-members/teamMembers.api.service';
import { colors } from '@/styles/colors';
import { evt_people_refresh_click, evt_people_delete, evt_settings_teams_visit } from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const TeamMembersSettings = () => {
const { t } = useTranslation('settings/team-members');
const dispatch = useAppDispatch();
const { socket } = useSocket();
const refreshTeamMembers = useAppSelector(state => state.memberReducer.refreshTeamMembers); // Listen to refresh flag
const { trackMixpanelEvent } = useMixpanelTracking();
const [model, setModel] = useState<ITeamMembersViewModel>({ total: 0, data: [] });
const [searchQuery, setSearchQuery] = useState<string>('');
@@ -96,6 +100,11 @@ const TeamMembersSettings = () => {
setIsLoading(true);
const res = await teamMembersApiService.delete(record.id);
if (res.done) {
trackMixpanelEvent(evt_people_delete, {
member_id: record.id,
member_name: record.name,
});
await getTeamMembers();
}
} finally {
@@ -114,6 +123,9 @@ const TeamMembersSettings = () => {
const handleRefresh = useCallback(() => {
setIsLoading(true);
trackMixpanelEvent(evt_people_refresh_click);
getTeamMembers().finally(() => setIsLoading(false));
}, [getTeamMembers]);
@@ -152,6 +164,8 @@ const TeamMembersSettings = () => {
}, [refreshTeamMembers, handleRefresh]);
useEffect(() => {
trackMixpanelEvent(evt_settings_teams_visit);
getTeamMembers();
}, [getTeamMembers]);
@@ -340,10 +354,7 @@ const TeamMembersSettings = () => {
/>
</Card>
{createPortal(
<UpdateMemberDrawer
selectedMemberId={selectedMemberId}
onRoleUpdate={handleRoleUpdate}
/>,
<UpdateMemberDrawer selectedMemberId={selectedMemberId} onRoleUpdate={handleRoleUpdate} />,
document.body
)}
</div>

View File

@@ -11,6 +11,9 @@ import { useAppDispatch } from '@/hooks/useAppDispatch';
import { useDocumentTitle } from '@/hooks/useDoumentTItle';
import { ITeamGetResponse } from '@/types/teams/team.type';
import { evt_settings_teams_visit } from '@/shared/worklenz-analytics-events';
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
const TeamsSettings = () => {
useDocumentTitle('Teams');
@@ -18,8 +21,11 @@ const TeamsSettings = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const { teamsList } = useAppSelector(state => state.teamReducer);
const dispatch = useAppDispatch();
const { trackMixpanelEvent } = useMixpanelTracking();
useEffect(() => {
trackMixpanelEvent(evt_settings_teams_visit);
dispatch(fetchTeams());
}, [dispatch]);