Add desk-style task workflow on Activities and Project boards.
Managers can switch my desk vs team, reassign activities, and filter project cards to their work; assignees can see and move cards.
This commit is contained in:
@@ -211,27 +211,27 @@ export const NAV_HUBS: NavHubDef[] = [
|
||||
},
|
||||
{
|
||||
key: 'activities',
|
||||
title: 'فعالیتها',
|
||||
desc: 'کارها، تماسها و برنامهریزی روزانه',
|
||||
title: 'کارها و فعالیتها',
|
||||
desc: 'میز کار شخصی، ارجاع و پیگیری روزانه',
|
||||
icon: 'check',
|
||||
tint: 'sky',
|
||||
shortcuts: [
|
||||
{ to: '/activities/new', title: 'فعالیت جدید', icon: 'plus', module: 'activities' },
|
||||
{ to: '/activities/new', title: 'کار جدید', icon: 'plus', module: 'activities' },
|
||||
{ to: '/activities/calendar', title: 'تقویم', icon: 'calendar', module: 'activities' },
|
||||
],
|
||||
cards: [
|
||||
{
|
||||
to: '/activities',
|
||||
title: 'فعالیتهای من',
|
||||
desc: 'کارها، تماسها و پیگیریهای جاری',
|
||||
title: 'میز کار من',
|
||||
desc: 'وظایف، تماسها و پیگیریهای جاری',
|
||||
icon: 'check',
|
||||
tint: 'mint',
|
||||
module: 'activities',
|
||||
},
|
||||
{
|
||||
to: '/activities/calendar',
|
||||
title: 'تقویم فعالیتها',
|
||||
desc: 'نمای روز، هفته و زمانبندی کارها',
|
||||
title: 'تقویم کارها',
|
||||
desc: 'نمای روز، هفته و زمانبندی',
|
||||
icon: 'calendar',
|
||||
tint: 'violet',
|
||||
module: 'activities',
|
||||
@@ -330,7 +330,7 @@ export const NAV_HUBS: NavHubDef[] = [
|
||||
{
|
||||
to: '/projects',
|
||||
title: 'کاریز پروژه',
|
||||
desc: 'کارتها و مراحل اجرای کار',
|
||||
desc: 'میز کار تیمی: صف، انجام، بازبینی و ارجاع کارت',
|
||||
icon: 'flag',
|
||||
tint: 'violet',
|
||||
module: 'project_boards',
|
||||
|
||||
@@ -12,6 +12,8 @@ export type PipelineDeal = {
|
||||
currencyUnit?: string;
|
||||
/** نام مسئولان برای نمایش روی کارت */
|
||||
assigneeNames?: string[];
|
||||
ownerId?: string | null;
|
||||
assigneeIds?: string[];
|
||||
};
|
||||
|
||||
export type PipelineUiCopy = {
|
||||
@@ -206,6 +208,8 @@ export function mapProjectBoardToStages(
|
||||
person: { fullName: string } | null;
|
||||
company: { name: string } | null;
|
||||
deal: { title: string } | null;
|
||||
owner?: { id: string; fullName: string } | null;
|
||||
assignees?: Array<{ id: string; fullName: string }>;
|
||||
}>;
|
||||
}>;
|
||||
},
|
||||
@@ -215,22 +219,33 @@ export function mapProjectBoardToStages(
|
||||
id: stage.id,
|
||||
title: stage.name,
|
||||
color: ACCENT_CYCLE[index % ACCENT_CYCLE.length]!,
|
||||
deals: stage.cards.map((card) => ({
|
||||
id: card.id,
|
||||
title: card.title,
|
||||
description:
|
||||
card.company?.name ||
|
||||
card.person?.fullName ||
|
||||
card.deal?.title ||
|
||||
card.notes?.trim() ||
|
||||
'',
|
||||
amount: null,
|
||||
date: formatDate(card.createdAt),
|
||||
initials: initialsFromTitle(
|
||||
card.company?.name || card.person?.fullName || card.title,
|
||||
),
|
||||
stageId: card.stageId,
|
||||
})),
|
||||
deals: stage.cards.map((card) => {
|
||||
const assigneeNames = [
|
||||
...(card.owner?.fullName ? [card.owner.fullName] : []),
|
||||
...(card.assignees ?? [])
|
||||
.map((a) => a.fullName)
|
||||
.filter((n) => n && n !== card.owner?.fullName),
|
||||
];
|
||||
return {
|
||||
id: card.id,
|
||||
title: card.title,
|
||||
description:
|
||||
card.company?.name ||
|
||||
card.person?.fullName ||
|
||||
card.deal?.title ||
|
||||
card.notes?.trim() ||
|
||||
'',
|
||||
amount: null,
|
||||
date: formatDate(card.createdAt),
|
||||
initials: initialsFromTitle(
|
||||
card.company?.name || card.person?.fullName || card.title,
|
||||
),
|
||||
stageId: card.stageId,
|
||||
assigneeNames,
|
||||
ownerId: card.owner?.id ?? null,
|
||||
assigneeIds: (card.assignees ?? []).map((a) => a.id),
|
||||
};
|
||||
}),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -292,6 +307,8 @@ export type PipelineBoardFilter = {
|
||||
query?: string;
|
||||
amountMin?: number | null;
|
||||
amountMax?: number | null;
|
||||
/** اگر ست باشد فقط کارتهای مربوط به این کاربر (مالک یا مسئول) */
|
||||
mineUserId?: string | null;
|
||||
};
|
||||
|
||||
export function filterStagesByQuery(
|
||||
@@ -308,14 +325,22 @@ export function filterStages(
|
||||
const q = filter.query?.trim().toLowerCase() ?? '';
|
||||
const min = filter.amountMin;
|
||||
const max = filter.amountMax;
|
||||
const mineUserId = filter.mineUserId?.trim() || null;
|
||||
const hasFilter =
|
||||
Boolean(q) ||
|
||||
Boolean(mineUserId) ||
|
||||
(min != null && !Number.isNaN(min)) ||
|
||||
(max != null && !Number.isNaN(max));
|
||||
if (!hasFilter) return stages;
|
||||
return stages.map((stage) => ({
|
||||
...stage,
|
||||
deals: stage.deals.filter((d) => {
|
||||
if (mineUserId) {
|
||||
const isMine =
|
||||
d.ownerId === mineUserId ||
|
||||
(d.assigneeIds ?? []).includes(mineUserId);
|
||||
if (!isMine) return false;
|
||||
}
|
||||
if (
|
||||
q &&
|
||||
!d.title.toLowerCase().includes(q) &&
|
||||
|
||||
Reference in New Issue
Block a user