diff --git a/frontend/src/pages/Dashboard/QuoteCard.tsx b/frontend/src/pages/Dashboard/QuoteCard.tsx
index 249ae5b..882d134 100644
--- a/frontend/src/pages/Dashboard/QuoteCard.tsx
+++ b/frontend/src/pages/Dashboard/QuoteCard.tsx
@@ -24,6 +24,7 @@ export interface QuoteCardProps {
onToggleExpand: () => void;
onAccept: () => void;
onEdit: () => void;
+ canWrite?: boolean;
}
function InfoCell({ label, children, className }: { label: string; children: React.ReactNode; className?: string }) {
@@ -35,7 +36,7 @@ function InfoCell({ label, children, className }: { label: string; children: Rea
);
}
-export function QuoteCard({ store, q, expanded, onToggleExpand, onAccept, onEdit }: QuoteCardProps) {
+export function QuoteCard({ store, q, expanded, onToggleExpand, onAccept, onEdit, canWrite = true }: QuoteCardProps) {
const sup = supplierById(store.suppliers, q.supplier_id);
const expired = isExpired(q);
const total = quoteTotal(q);
@@ -46,7 +47,7 @@ export function QuoteCard({ store, q, expanded, onToggleExpand, onAccept, onEdit
// ستون / دکمه پذیرش
let acceptedCell: React.ReactNode;
if (q.status === "offered") {
- acceptedCell = (
+ acceptedCell = canWrite ? (
+ ) : (
+
در انتظار پذیرش
);
} else if (q.accepted_date) {
acceptedCell =
{fmtDateTime(q.accepted_date)};
@@ -185,19 +188,21 @@ export function QuoteCard({ store, q, expanded, onToggleExpand, onAccept, onEdit
)}
{/* دکمه ویرایش */}
-
+ {canWrite && (
+
+ )}
{/* دکمه فلش اکسپند در هدر */}
}
- menu={
}
+ menu={
}
actions={
diff --git a/frontend/src/pages/Projects/ProjectsPage.tsx b/frontend/src/pages/Projects/ProjectsPage.tsx
index 31d3946..e498572 100644
--- a/frontend/src/pages/Projects/ProjectsPage.tsx
+++ b/frontend/src/pages/Projects/ProjectsPage.tsx
@@ -25,6 +25,7 @@ import { faNum, fmtDate } from "../../lib/formatters";
import { Header, PageLayout } from "../../components/layout/Header";
import { EmptyState } from "../../components/EmptyState";
import { Button } from "../../components/ui/button";
+import { useAuthStore } from "../../store/auth";
function projectQuotes(quotes: Quote[], name: string): Quote[] {
return quotes.filter(
@@ -83,6 +84,8 @@ export function ProjectsPage() {
const { standardConversions } = useUnits();
const addProject = useAddProject();
const topics = useAppStore((s) => s.topics);
+ const user = useAuthStore((s) => s.user);
+ const canManage = user?.role === "admin" || user?.role === "procurement_manager";
const store: Store = { quotes, suppliers, materials, projects, standardConversions, topics };
@@ -90,6 +93,7 @@ export function ProjectsPage() {
const [newName, setNewName] = useState("");
const addProj = () => {
+ if (!canManage) return;
const name = newName.trim();
if (!name) return;
const dup = projects.some((p) => normalize(p.name) === normalize(name));
@@ -108,29 +112,31 @@ export function ProjectsPage() {
-
-
+ افزودن پروژهی جدید
-
-
-
-
setNewName(e.target.value)}
- onKeyDown={(e) => {
- if (e.key === "Enter") {
- e.preventDefault();
- addProj();
- }
- }}
- />
+ {canManage && (
+
+
+ افزودن پروژهی جدید
+
+
+
+ setNewName(e.target.value)}
+ onKeyDown={(e) => {
+ if (e.key === "Enter") {
+ e.preventDefault();
+ addProj();
+ }
+ }}
+ />
+
+
-
-
+ )}
{!projects.length && !quotes.length ? (
diff --git a/frontend/src/pages/Suppliers/CategoryPage.tsx b/frontend/src/pages/Suppliers/CategoryPage.tsx
index e22320e..a1d2f71 100644
--- a/frontend/src/pages/Suppliers/CategoryPage.tsx
+++ b/frontend/src/pages/Suppliers/CategoryPage.tsx
@@ -14,6 +14,7 @@ import { Combobox } from "../../components/Combobox";
import { SupplierCard, suppliersOfCategory } from "./supplierUtils";
import { materialLabel } from "../../lib/quoteUtils";
import { Button } from "../../components/ui/button";
+import { useAuthStore } from "../../store/auth";
// صفحهی تأمینکنندههای یک دسته + فرم افزودن تأمینکننده
export function CategoryPage() {
@@ -26,6 +27,8 @@ export function CategoryPage() {
const addSupplier = useAddSupplier();
const removeSupplier = useRemoveSupplier();
const topics = useAppStore((s) => s.topics);
+ const user = useAuthStore((s) => s.user);
+ const canManage = user?.role === "admin" || user?.role === "procurement_manager";
const cat = useMemo(() => topicByName(catParam, topics)?.name ?? null, [catParam, topics]);
@@ -121,7 +124,7 @@ export function CategoryPage() {
key={s.id}
s={s}
topic={cat}
- deletable
+ deletable={canManage}
onDelete={removeSup}
materials={supMats.get(s.id) || []}
avgLeadTime={supLeadTimes.get(s.id)}
@@ -130,10 +133,11 @@ export function CategoryPage() {
)}
-
-
- افزودن تأمینکنندهی جدید
-
+ {canManage && (
+
+
+ افزودن تأمینکنندهی جدید
+
@@ -182,6 +186,7 @@ export function CategoryPage() {
ذخیره تأمینکننده
+ )}
);
diff --git a/frontend/src/pages/Suppliers/SupplierDetailPage.tsx b/frontend/src/pages/Suppliers/SupplierDetailPage.tsx
index 6fe0d83..45f679a 100644
--- a/frontend/src/pages/Suppliers/SupplierDetailPage.tsx
+++ b/frontend/src/pages/Suppliers/SupplierDetailPage.tsx
@@ -14,6 +14,7 @@ import { MultiSelectCombobox } from "../../components/MultiSelectCombobox";
import { ConfirmDeleteDialog } from "../../components/ConfirmDeleteDialog";
import { normalize } from "../../lib/normalize";
import { PurchaseHistory } from "./PurchaseHistory";
+import { useAuthStore } from "../../store/auth";
// تمیزکاری و استانداردسازی شماره برای شمارهگیر خودکار موبایل (اندروید و iOS)
function cleanPhoneForTel(phone?: string | null): string {
@@ -32,6 +33,8 @@ export function SupplierDetailPage() {
const quotes = useQuotes();
const materials = useMaterials();
const topics = useAppStore((s) => s.topics);
+ const user = useAuthStore((s) => s.user);
+ const canManage = user?.role === "admin" || user?.role === "procurement_manager";
const s = useMemo(() => suppliers.find((x) => x.id === id) || null, [suppliers, id]);
const [pendingRemove, setPendingRemove] = useState
(null);
@@ -184,13 +187,15 @@ export function SupplierDetailPage() {
-
-
- پیشنهاد جدید
-
+ {canManage && (
+
+
+ پیشنهاد جدید
+
+ )}
{firstCat ? (
‹ بازگشت به دسته
@@ -216,19 +221,23 @@ export function SupplierDetailPage() {
{linked.map((c) => (
{c}
-
+ {canManage && (
+
+ )}
))}
)}
-
saveCategories(cats)}
- options={materialOptions}
- placeholder="افزودن متریال..."
- />
+ {canManage && (
+ saveCategories(cats)}
+ options={materialOptions}
+ placeholder="افزودن متریال..."
+ />
+ )}
{purchased.length > 0 && (
متریالهای خریداریشده (از پیشنهادها):