Task #668: Rename Protocol side-menu items (bilingual AR/EN)
Relabeled three Protocol (العلاقات العامة والمراسم) menu items to match real usage:
- photos: "تصوير" -> "الصور" / "Photos"
- gifts (item catalog where أصناف are added): "الإهداءات" -> "المستودع" / "Warehouse"
- issues (giving gifts out): "طلبات الصرف" -> "الإهداءات" / "Dedications"
Swapped menu icons to match new meanings: gifts->Warehouse, issues->Gift,
photos->ImageIcon. Removed now-unused imports (PackageCheck, Camera).
Grouped المستودع + الإهداءات under one expandable submenu (parent label
"الهدايا"/"Gifts", new i18n key protocol.tabs.giftsGroup, HandHeart icon,
ChevronDown toggle). Group auto-expands when a child tab is active; state
giftsGroupOpen. RTL-aware (ms-auto chevron, md:ps-6 child indent).
Aligned in-screen wording with new names in both locales:
dashboard.pendingIssues, issues.new, issues.empty reworded from
issuance/صرف to dedication/إهداء.
Deviation: submenu grouping and parent-group naming ("الهدايا") were an
interpretation of the user's "sub-menu" request (user_query was unavailable
during planning). Kept scope tight: remaining secondary "issuance/صرف"
strings in reports/actions/dashboard stats (e.g. giftsIssuedThisMonth,
actions.issued, reports.byGift) were left unchanged and proposed as a
follow-up.
Unchanged (deliberately): internal tab keys (gifts/issues/photos) and URL
slugs (gifts, gift-issues, photos) so deep links keep working. No feature,
API, or data changes.
Verified: pnpm --filter @workspace/tx-os run typecheck passes; architect
code review passed after issues icon corrected to Gift.
This commit is contained in:
@@ -1669,9 +1669,10 @@
|
||||
"dashboard": "لوحة المعلومات",
|
||||
"bookings": "حجوزات القاعات",
|
||||
"external": "اللقاءات الخارجية",
|
||||
"gifts": "الإهداءات",
|
||||
"issues": "طلبات الصرف",
|
||||
"photos": "تصوير",
|
||||
"giftsGroup": "الهدايا",
|
||||
"gifts": "المستودع",
|
||||
"issues": "الإهداءات",
|
||||
"photos": "الصور",
|
||||
"reports": "التقارير",
|
||||
"audit": "سجل النشاط",
|
||||
"rooms": "القاعات"
|
||||
@@ -1704,7 +1705,7 @@
|
||||
"pendingBookings": "حجوزات بانتظار الاعتماد",
|
||||
"upcomingExternal": "لقاءات خارجية قادمة",
|
||||
"giftStock": "إجمالي مخزون الهدايا",
|
||||
"pendingIssues": "طلبات صرف معلّقة",
|
||||
"pendingIssues": "إهداءات معلّقة",
|
||||
"roomsAvailableNow": "القاعات المتاحة الآن",
|
||||
"giftsIssuedThisMonth": "الدروع المصروفة هذا الشهر"
|
||||
},
|
||||
@@ -1763,8 +1764,8 @@
|
||||
"empty": "لا توجد قاعات."
|
||||
},
|
||||
"issues": {
|
||||
"new": "طلب صرف",
|
||||
"empty": "لا توجد طلبات صرف.",
|
||||
"new": "إهداء جديد",
|
||||
"empty": "لا توجد إهداءات.",
|
||||
"recipient": "المستفيد",
|
||||
"gift": "الصنف",
|
||||
"occasion": "المناسبة",
|
||||
|
||||
@@ -1542,8 +1542,9 @@
|
||||
"dashboard": "Dashboard",
|
||||
"bookings": "Room Bookings",
|
||||
"external": "External Meetings",
|
||||
"gifts": "Dedications",
|
||||
"issues": "Issuance Requests",
|
||||
"giftsGroup": "Gifts",
|
||||
"gifts": "Warehouse",
|
||||
"issues": "Dedications",
|
||||
"photos": "Photos",
|
||||
"reports": "Reports",
|
||||
"audit": "Activity Log",
|
||||
@@ -1577,7 +1578,7 @@
|
||||
"pendingBookings": "Bookings awaiting approval",
|
||||
"upcomingExternal": "Upcoming external meetings",
|
||||
"giftStock": "Total gift stock",
|
||||
"pendingIssues": "Pending issuance requests",
|
||||
"pendingIssues": "Pending dedications",
|
||||
"roomsAvailableNow": "Rooms available now",
|
||||
"giftsIssuedThisMonth": "Gifts issued this month"
|
||||
},
|
||||
@@ -1636,8 +1637,8 @@
|
||||
"empty": "No rooms."
|
||||
},
|
||||
"issues": {
|
||||
"new": "Issuance request",
|
||||
"empty": "No issuance requests yet.",
|
||||
"new": "New dedication",
|
||||
"empty": "No dedications yet.",
|
||||
"recipient": "Recipient",
|
||||
"gift": "Item",
|
||||
"occasion": "Occasion",
|
||||
|
||||
@@ -10,6 +10,9 @@ import {
|
||||
CalendarClock,
|
||||
Handshake,
|
||||
Gift,
|
||||
Warehouse,
|
||||
HandHeart,
|
||||
ChevronDown,
|
||||
BarChart3,
|
||||
ScrollText,
|
||||
Plus,
|
||||
@@ -17,12 +20,10 @@ import {
|
||||
Trash2,
|
||||
Check,
|
||||
X,
|
||||
PackageCheck,
|
||||
CalendarDays,
|
||||
List as ListIcon,
|
||||
Link2,
|
||||
Copy,
|
||||
Camera,
|
||||
Upload,
|
||||
Loader2,
|
||||
Download,
|
||||
@@ -632,6 +633,7 @@ export default function ProtocolPage() {
|
||||
const [issueDialog, setIssueDialog] = useState<{ open: boolean }>({
|
||||
open: false,
|
||||
});
|
||||
const [giftsGroupOpen, setGiftsGroupOpen] = useState(false);
|
||||
|
||||
const bookingAction = useMutation({
|
||||
mutationFn: (args: { id: number; action: "approve" | "cancel" }) =>
|
||||
@@ -712,9 +714,9 @@ export default function ProtocolPage() {
|
||||
{ key: "rooms", label: t("protocol.tabs.rooms"), icon: DoorOpen },
|
||||
{ key: "bookings", label: t("protocol.tabs.bookings"), icon: CalendarClock },
|
||||
{ key: "external", label: t("protocol.tabs.external"), icon: Handshake },
|
||||
{ key: "gifts", label: t("protocol.tabs.gifts"), icon: Gift },
|
||||
{ key: "issues", label: t("protocol.tabs.issues"), icon: PackageCheck },
|
||||
{ key: "photos", label: t("protocol.tabs.photos"), icon: Camera },
|
||||
{ key: "gifts", label: t("protocol.tabs.gifts"), icon: Warehouse },
|
||||
{ key: "issues", label: t("protocol.tabs.issues"), icon: Gift },
|
||||
{ key: "photos", label: t("protocol.tabs.photos"), icon: ImageIcon },
|
||||
{ key: "reports", label: t("protocol.tabs.reports"), icon: BarChart3 },
|
||||
...(c?.canViewAudit
|
||||
? [{ key: "audit" as TabKey, label: t("protocol.tabs.audit"), icon: ScrollText }]
|
||||
@@ -851,21 +853,73 @@ export default function ProtocolPage() {
|
||||
<div className="max-w-6xl mx-auto px-4 py-5 flex flex-col md:flex-row gap-4 md:gap-6">
|
||||
<aside className="md:w-56 shrink-0">
|
||||
<nav className="flex md:flex-col gap-1 overflow-x-auto md:overflow-visible pb-2 md:pb-0 md:sticky md:top-20">
|
||||
{TABS.map(({ key, label, icon: Icon }) => (
|
||||
<button
|
||||
key={key}
|
||||
onClick={() => setTab(key)}
|
||||
className={cn(
|
||||
"flex items-center gap-2 px-3 py-2 rounded-lg text-sm whitespace-nowrap transition-colors md:w-full md:justify-start",
|
||||
tab === key
|
||||
? "bg-sky-500 text-white"
|
||||
: "text-slate-600 hover:bg-slate-100",
|
||||
)}
|
||||
>
|
||||
<Icon size={16} className="shrink-0" />
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
{TABS.map((item) => {
|
||||
const { key, label, icon: Icon } = item;
|
||||
if (key === "issues") return null;
|
||||
if (key === "gifts") {
|
||||
const children = TABS.filter(
|
||||
(x) => x.key === "gifts" || x.key === "issues",
|
||||
);
|
||||
const groupActive = children.some((x) => x.key === tab);
|
||||
const open = giftsGroupOpen || groupActive;
|
||||
return (
|
||||
<div key="giftsGroup" className="flex md:flex-col gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setGiftsGroupOpen((v) => !v)}
|
||||
aria-expanded={open}
|
||||
className={cn(
|
||||
"flex items-center gap-2 px-3 py-2 rounded-lg text-sm whitespace-nowrap transition-colors md:w-full md:justify-start",
|
||||
groupActive
|
||||
? "text-sky-600 font-medium"
|
||||
: "text-slate-600 hover:bg-slate-100",
|
||||
)}
|
||||
>
|
||||
<HandHeart size={16} className="shrink-0" />
|
||||
{t("protocol.tabs.giftsGroup")}
|
||||
<ChevronDown
|
||||
size={14}
|
||||
className={cn(
|
||||
"ms-auto shrink-0 transition-transform",
|
||||
open && "rotate-180",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
{open &&
|
||||
children.map(({ key: ck, label: cl, icon: CIcon }) => (
|
||||
<button
|
||||
key={ck}
|
||||
onClick={() => setTab(ck)}
|
||||
className={cn(
|
||||
"flex items-center gap-2 px-3 py-2 rounded-lg text-sm whitespace-nowrap transition-colors md:w-full md:justify-start md:ps-6",
|
||||
tab === ck
|
||||
? "bg-sky-500 text-white"
|
||||
: "text-slate-600 hover:bg-slate-100",
|
||||
)}
|
||||
>
|
||||
<CIcon size={16} className="shrink-0" />
|
||||
{cl}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<button
|
||||
key={key}
|
||||
onClick={() => setTab(key)}
|
||||
className={cn(
|
||||
"flex items-center gap-2 px-3 py-2 rounded-lg text-sm whitespace-nowrap transition-colors md:w-full md:justify-start",
|
||||
tab === key
|
||||
? "bg-sky-500 text-white"
|
||||
: "text-slate-600 hover:bg-slate-100",
|
||||
)}
|
||||
>
|
||||
<Icon size={16} className="shrink-0" />
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user