refactor(dashboard): drop the services list from the staff dashboard
The assigned-services card and its stat card are gone. The staff role has one job — today's sessions — and with /admin/my-services already removed, a list of services the operator cannot act on was the last thing on the page competing with the work itself. The remaining stat card no longer stretches the page: `.stat-grid` is built for four cards and collapses to one full-width column with a single child, so the staff grid is capped. The endpoint still returns `services` and `stats.services`; the field is documented and cheap, and nothing else needed to change to stop rendering it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -220,14 +220,20 @@ describe('داشبورد پرسنل', () => {
|
||||
expect(screen.getByText('محمد رستمی')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('کارت جلسات لینک است و کارت سرویسها نیست', async () => {
|
||||
it('کارت جلسات لینک است', async () => {
|
||||
renderWithProviders(<DashboardPage />);
|
||||
|
||||
const sessions = (await screen.findByText('جلسات امروز من')).closest('a');
|
||||
expect(sessions).toHaveAttribute('href', '/admin/my-sessions');
|
||||
});
|
||||
|
||||
// صفحهٔ «سرویسهای من» حذف شد؛ کارتِ بدون مقصد نباید لینک باشد.
|
||||
expect(screen.getByText('سرویسهای من').closest('a')).toBeNull();
|
||||
/** سرویسها کارِ اپراتور نیستند؛ داشبورد فقط کارِ امروز را نشان میدهد. */
|
||||
it('هیچجای داشبورد سرویسها را نشان نمیدهد', async () => {
|
||||
renderWithProviders(<DashboardPage />);
|
||||
await screen.findByText('محمد رسولی');
|
||||
|
||||
expect(screen.queryByText('سرویسهای من')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('سرویسهای تخصیصیافته')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('هر ردیف کار به همان جلسه میرود', async () => {
|
||||
|
||||
@@ -1015,13 +1015,6 @@ function StaffDashboard() {
|
||||
hint: sessions.length > 0 ? `${formatNumber(settled)} انجام شده` : 'کاری برای امروز نیست',
|
||||
icon: CalendarDaysIcon, color: 'var(--warning)', bg: 'var(--warning-bg)',
|
||||
},
|
||||
{
|
||||
to: null,
|
||||
label: 'سرویسهای من',
|
||||
value: formatNumber(d.stats?.services ?? 0),
|
||||
hint: 'سرویسهایی که مجاز به انجامشان هستید',
|
||||
icon: ClockIcon, color: 'var(--info)', bg: 'var(--info-bg)',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -1044,25 +1037,19 @@ function StaffDashboard() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="stat-grid">
|
||||
{kpiCards.map(c => {
|
||||
const body = (
|
||||
<>
|
||||
<div className="ico" style={{ background: c.bg, color: c.color }}>
|
||||
<c.icon style={{ width: 21, height: 21 }} />
|
||||
</div>
|
||||
<div className="lbl">{c.label}</div>
|
||||
<div className="val">{c.value}</div>
|
||||
<div className="hint">{c.hint}</div>
|
||||
</>
|
||||
);
|
||||
|
||||
// فقط کارتی لینک میشود که صفحهای پشتش باشد؛ سرویسها صفحهٔ جدا ندارند و
|
||||
// همینجا پایینتر فهرست میشوند.
|
||||
return c.to === null
|
||||
? <div key={c.label} className="stat">{body}</div>
|
||||
: <Link key={c.label} to={c.to} className="stat" style={{ display: 'block', color: 'inherit', textDecoration: 'none' }}>{body}</Link>;
|
||||
})}
|
||||
{/* یک کارت تنها نباید تمام عرض صفحه را بگیرد؛ `.stat-grid` برای چهار کارت
|
||||
طراحی شده و با یک فرزند به یک ستونِ تمامعرض تبدیل میشود. */}
|
||||
<div className="stat-grid" style={{ maxWidth: 360 }}>
|
||||
{kpiCards.map(c => (
|
||||
<Link key={c.label} to={c.to} className="stat" style={{ display: 'block', color: 'inherit', textDecoration: 'none' }}>
|
||||
<div className="ico" style={{ background: c.bg, color: c.color }}>
|
||||
<c.icon style={{ width: 21, height: 21 }} />
|
||||
</div>
|
||||
<div className="lbl">{c.label}</div>
|
||||
<div className="val">{c.value}</div>
|
||||
<div className="hint">{c.hint}</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="card card-pad" style={{ marginTop: 'var(--gap)' }}>
|
||||
@@ -1107,28 +1094,6 @@ function StaffDashboard() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="card card-pad" style={{ marginTop: 'var(--gap)' }}>
|
||||
<div className="card-title-row">
|
||||
<h3 style={{ fontSize: 16 }}>سرویسهای تخصیصیافته</h3>
|
||||
</div>
|
||||
{d.services.length === 0 ? (
|
||||
<p className="muted" style={{ fontSize: 13.5, padding: '1.5rem 0', textAlign: 'center' }}>
|
||||
هنوز سرویسی به شما تخصیص نیافته است.
|
||||
</p>
|
||||
) : (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 8 }}>
|
||||
{d.services.slice(0, 5).map(s => (
|
||||
<div key={s.uuid} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 12px', borderRadius: 'var(--r-sm)', background: 'var(--surface-2)' }}>
|
||||
<div>
|
||||
<div style={{ fontWeight: 600, fontSize: 14 }}>{s.name}</div>
|
||||
<div className="muted" style={{ fontSize: 12, marginTop: 2 }}>{s.section_name}</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 13 }}>{formatRial(s.price_rials)}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* نوبتِ مستقیمِ اختصاصیافته فقط وقتی نشان داده میشود که وجود داشته باشد؛
|
||||
یک جدول همیشه-خالی زیر کارِ واقعی، فقط صفحه را بلند میکرد. */}
|
||||
|
||||
Reference in New Issue
Block a user