Redesign sales pipeline UI and reconnect it to live board APIs.
Keep the employer kanban layout while loading pipelines/deals from the server, persisting drag-and-drop moves, and seeding a Waiting pipeline with demo deals. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -239,6 +239,172 @@ async function main() {
|
||||
console.log('Services pipeline already seeded');
|
||||
}
|
||||
|
||||
// کاریز منتظر — مطابق طراحی UI (۳ مرحله + معاملات نمونه)
|
||||
const WAITING_STAGES = [
|
||||
{ name: 'پیگیری', isWon: false, isLost: false },
|
||||
{ name: 'مذاکرات اولیه', isWon: false, isLost: false },
|
||||
{ name: 'قیمت و نهایی کردن', isWon: false, isLost: false },
|
||||
] as const;
|
||||
|
||||
const WAITING_DEALS: Array<{
|
||||
stageName: (typeof WAITING_STAGES)[number]['name'];
|
||||
title: string;
|
||||
notes: string;
|
||||
amount: number;
|
||||
expectedCloseAt: string;
|
||||
position: number;
|
||||
}> = [
|
||||
{
|
||||
stageName: 'پیگیری',
|
||||
title: 'نرمافزار حسابان',
|
||||
notes: 'نصب سیستم یکپارچه',
|
||||
amount: 250_000_000,
|
||||
expectedCloseAt: '2024-07-15T00:00:00.000Z',
|
||||
position: 0,
|
||||
},
|
||||
{
|
||||
stageName: 'پیگیری',
|
||||
title: 'همکاران سیستم',
|
||||
notes: 'نسخه سازمانی',
|
||||
amount: 350_000_000,
|
||||
expectedCloseAt: '2024-07-08T00:00:00.000Z',
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
stageName: 'پیگیری',
|
||||
title: 'بازرگانی امید',
|
||||
notes: 'کاربران سازمانی',
|
||||
amount: 180_000_000,
|
||||
expectedCloseAt: '2024-07-17T00:00:00.000Z',
|
||||
position: 2,
|
||||
},
|
||||
{
|
||||
stageName: 'پیگیری',
|
||||
title: 'کالای صنعتی پارس',
|
||||
notes: 'ماژول انبارداری',
|
||||
amount: 120_000_000,
|
||||
expectedCloseAt: '2024-07-23T00:00:00.000Z',
|
||||
position: 3,
|
||||
},
|
||||
{
|
||||
stageName: 'مذاکرات اولیه',
|
||||
title: 'فروشگاه تککالا',
|
||||
notes: 'ماژول فروش',
|
||||
amount: 280_000_000,
|
||||
expectedCloseAt: '2024-07-13T00:00:00.000Z',
|
||||
position: 0,
|
||||
},
|
||||
{
|
||||
stageName: 'مذاکرات اولیه',
|
||||
title: 'شرکت دادهپرداز',
|
||||
notes: 'اتصال به حسابداری',
|
||||
amount: 190_000_000,
|
||||
expectedCloseAt: '2024-07-10T00:00:00.000Z',
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
stageName: 'مذاکرات اولیه',
|
||||
title: 'گروه فنی مهندسی آوا',
|
||||
notes: 'ماژول پروژهها',
|
||||
amount: 315_000_000,
|
||||
expectedCloseAt: '2024-07-05T00:00:00.000Z',
|
||||
position: 2,
|
||||
},
|
||||
{
|
||||
stageName: 'مذاکرات اولیه',
|
||||
title: 'رستوران زنجیرهای نیک',
|
||||
notes: 'ماژول رستوران',
|
||||
amount: 165_000_000,
|
||||
expectedCloseAt: '2024-07-09T00:00:00.000Z',
|
||||
position: 3,
|
||||
},
|
||||
{
|
||||
stageName: 'قیمت و نهایی کردن',
|
||||
title: 'شرکت تجارت',
|
||||
notes: 'یکپارچهسازی کامل',
|
||||
amount: 640_000_000,
|
||||
expectedCloseAt: '2024-06-30T00:00:00.000Z',
|
||||
position: 0,
|
||||
},
|
||||
{
|
||||
stageName: 'قیمت و نهایی کردن',
|
||||
title: 'فروشگاه اینترنتی دیجیخونه',
|
||||
notes: 'فروشگاه اینترنتی',
|
||||
amount: 420_000_000,
|
||||
expectedCloseAt: '2024-06-28T00:00:00.000Z',
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
stageName: 'قیمت و نهایی کردن',
|
||||
title: 'شرکت داروسازی بهداشت',
|
||||
notes: 'ماژول مالی و انبار',
|
||||
amount: 780_000_000,
|
||||
expectedCloseAt: '2024-07-02T00:00:00.000Z',
|
||||
position: 2,
|
||||
},
|
||||
];
|
||||
|
||||
let waitingPipeline = await prisma.pipeline.findFirst({
|
||||
where: { organizationId: org.id, name: 'کاریز منتظر' },
|
||||
include: { stages: { orderBy: { position: 'asc' } } },
|
||||
});
|
||||
|
||||
if (!waitingPipeline) {
|
||||
waitingPipeline = await prisma.pipeline.create({
|
||||
data: {
|
||||
organizationId: org.id,
|
||||
name: 'کاریز منتظر',
|
||||
isDefault: false,
|
||||
stages: {
|
||||
create: WAITING_STAGES.map((s, index) => ({
|
||||
name: s.name,
|
||||
position: index,
|
||||
isWon: s.isWon,
|
||||
isLost: s.isLost,
|
||||
})),
|
||||
},
|
||||
},
|
||||
include: { stages: { orderBy: { position: 'asc' } } },
|
||||
});
|
||||
console.log('Seeded waiting pipeline (کاریز منتظر)');
|
||||
} else {
|
||||
console.log('Waiting pipeline already seeded');
|
||||
}
|
||||
|
||||
const waitingDealCount = await prisma.deal.count({
|
||||
where: { organizationId: org.id, pipelineId: waitingPipeline.id },
|
||||
});
|
||||
|
||||
if (waitingDealCount === 0) {
|
||||
const stageByName = new Map(
|
||||
waitingPipeline.stages.map((s) => [s.name, s] as const),
|
||||
);
|
||||
await prisma.deal.createMany({
|
||||
data: WAITING_DEALS.map((d) => {
|
||||
const stage = stageByName.get(d.stageName);
|
||||
if (!stage) {
|
||||
throw new Error(`Missing stage ${d.stageName} on waiting pipeline`);
|
||||
}
|
||||
return {
|
||||
organizationId: org.id,
|
||||
pipelineId: waitingPipeline!.id,
|
||||
stageId: stage.id,
|
||||
title: d.title,
|
||||
notes: d.notes,
|
||||
amount: d.amount,
|
||||
currency: 'IRR',
|
||||
expectedCloseAt: new Date(d.expectedCloseAt),
|
||||
ownerId: owner?.id,
|
||||
position: d.position,
|
||||
tags: ['دمو-کاریز'],
|
||||
};
|
||||
}),
|
||||
});
|
||||
console.log('Seeded waiting pipeline deals:', WAITING_DEALS.length);
|
||||
} else {
|
||||
console.log('Waiting pipeline deals already seeded');
|
||||
}
|
||||
|
||||
const dealsCount = await prisma.deal.count({
|
||||
where: { organizationId: org.id },
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user