feat(pricing): manage workspace member rates in edit flows

This commit is contained in:
2026-04-26 10:21:58 +03:30
parent f9dfd8826e
commit 2d843046fa
8 changed files with 665 additions and 213 deletions

View File

@@ -152,12 +152,12 @@ export const fa = {
emptyState: "شما در هیچ ورک‌اسپیس عضو نیستید.",
createTitle: "ایجاد ورک‌اسپیس",
editTitle: "ویرایش ورک‌اسپیس",
detailTitle: "جزئیات ورک‌اسپیس",
save: "ذخیره",
create: "ایجاد",
noWorkspaceTitle: "خوش آمدید!",
noWorkspaceDesc: "لطفاً اولین ورک‌اسپیس خود را ایجاد کنید.",
back: "بازگشت به ورک‌اسپیس‌ها",
detailTitle: "جزئیات ورک‌اسپیس",
save: "ذخیره",
create: "ایجاد",
noWorkspaceTitle: "خوش آمدید!",
noWorkspaceDesc: "لطفاً اولین ورک‌اسپیس خود را ایجاد کنید.",
back: "بازگشت به ورک‌اسپیس‌ها",
roleLabel: "نقش شما",
roles: {
owner: "مالک",
@@ -241,15 +241,15 @@ export const fa = {
next: "بعدی",
},
sidebar: {
timesheet: 'تایم‌شیت',
workspaces: 'ورک‌اسپیس‌ها',
clients: 'مشتریان',
projects: "پروژه‌ها",
tags: "تگ‌ها",
expand: 'باز کردن',
collapse: 'جمع کردن',
},
sidebar: {
timesheet: 'تایم‌شیت',
workspaces: 'ورک‌اسپیس‌ها',
clients: 'مشتریان',
projects: "پروژه‌ها",
tags: "تگ‌ها",
expand: 'باز کردن',
collapse: 'جمع کردن',
},
ordering: {
createdAtDesc: "جدیدترین",
@@ -259,7 +259,7 @@ export const fa = {
nameDesc: "نام (نزولی)",
},
projects: {
projects: {
title: "پروژه‌ها",
description: (workspaceName: string) => `مدیریت پروژه‌ها برای ${workspaceName}`,
active: "پروژه‌های فعال",
@@ -301,108 +301,129 @@ export const fa = {
},
namePlaceholder: "نام پروژه...",
teamMembers: "اعضای تیم",
createSuccess: "پروژه با موفقیت ایجاد شد.",
createError: "خطا در ایجاد پروژه.",
updateSuccess: "پروژه با موفقیت به‌روزرسانی شد.",
updateError: "به‌روزرسانی پروژه با خطا مواجه شد.",
edit: "ویرایش پروژه",
projectMembers: "اعضای پروژه",
createSuccess: "پروژه با موفقیت ایجاد شد.",
createError: "خطا در ایجاد پروژه.",
updateSuccess: "پروژه با موفقیت به‌روزرسانی شد.",
updateError: "به‌روزرسانی پروژه با خطا مواجه شد.",
edit: "ویرایش پروژه",
projectMembers: "اعضای پروژه",
removeAllWorkspaceMembers: "حذف همه",
searchWorkspaceMembers: "جستجو با نام یا وارد کردن شماره موبایل...",
userNotFound: "کاربری با این شماره موبایل یافت نشد.",
alreadyInProject: "قبلاً اضافه شده",
addToProject: "افزودن به پروژه",
noWorkspaceMembers: "عضوی یافت نشد.",
},
tags: {
title: "تگ‌ها",
description: (workspaceName: string) => `مدیریت تگ‌ها برای ${workspaceName}`,
create: "ایجاد تگ",
createTitle: "ایجاد تگ",
editTitle: "ویرایش تگ",
deleteTitle: "حذف تگ",
deleteConfirmMessage: (name: string) => `آیا از حذف ${name} اطمینان دارید؟`,
searchPlaceholder: "جست‌وجوی تگ‌ها...",
nameLabel: "نام تگ",
namePlaceholder: "مثلاً طراحی",
colorLabel: "رنگ",
emptyState: "تگی یافت نشد",
selectWorkspace: "لطفاً ابتدا یک ورک‌اسپیس انتخاب کنید.",
fetchError: "دریافت تگ‌ها با خطا مواجه شد.",
createSuccess: "تگ با موفقیت ایجاد شد.",
updateSuccess: "تگ با موفقیت به‌روزرسانی شد.",
saveError: "ذخیره تگ با خطا مواجه شد.",
deleteSuccess: "تگ با موفقیت حذف شد.",
deleteError: "حذف تگ با خطا مواجه شد.",
},
timesheet: {
title: "تایم‌شیت",
description: (workspaceName: string) => `ثبت زمان در ${workspaceName}`,
selectWorkspace: "لطفاً ابتدا یک ورک‌اسپیس انتخاب کنید.",
addEntry: "افزودن ورودی",
startTimer: "شروع تایمر",
stopTimer: "توقف تایمر",
timerRunning: "تایمر فعال است",
runningLabel: "تایمر فعلی",
runningBadge: "در حال اجرا",
noRunningEntry: "تایمر فعالی وجود ندارد",
searchPlaceholder: "جست‌وجوی ورودی‌های زمان...",
orderingNewest: "جدیدترین",
orderingOldest: "قدیمی‌ترین",
emptyState: "ورودی زمانی یافت نشد",
emptyDescription: "بدون توضیح",
createTitle: "افزودن ورودی زمان",
startTitle: "شروع تایمر",
editTitle: "ویرایش ورودی زمان",
createSuccess: "ورودی زمان با موفقیت ایجاد شد.",
startSuccess: "تایمر با موفقیت شروع شد.",
updateSuccess: "ورودی زمان با موفقیت به‌روزرسانی شد.",
saveError: "ذخیره ورودی زمان با خطا مواجه شد.",
stopSuccess: "تایمر با موفقیت متوقف شد.",
stopError: "توقف تایمر با خطا مواجه شد.",
deleteSuccess: "ورودی زمان با موفقیت حذف شد.",
deleteError: "حذف ورودی زمان با خطا مواجه شد.",
fetchError: "دریافت ورودی‌های زمان با خطا مواجه شد.",
optionsError: "دریافت پروژه‌ها و تگ‌ها با خطا مواجه شد.",
descriptionLabel: وضیحات",
descriptionPlaceholder: "روی چه چیزی کار می‌کنید؟",
projectLabel: "پروژه",
noProject: "بدون پروژه",
startLabel: "شروع",
endLabel: "پایان",
billable: "قابل صورتحساب",
noTagsHint: "ابتدا از صفحه تگ‌ها، تگ ایجاد کنید.",
clearFilters: "پاک کردن فیلترها",
customFromLabel: "از تاریخ",
customToLabel: "تا تاریخ",
allClientsLabel: "همه مشتری‌ها",
allProjectsLabel: "همه پروژه‌ها",
allTagsLabel: "همه تگ‌ها",
showFiltersLabel: "نمایش فیلترها",
hideFiltersLabel: "مخفی کردن فیلترها",
applyFiltersLabel: "اعمال",
clientFilterPrefix: "مشتری",
projectFilterPrefix: "پروژه",
tagFilterPrefix: "تگ",
fromFilterPrefix: "از",
toFilterPrefix: ا",
},
notifications: {
title: "اعلان‌ها",
open: "باز کردن اعلان‌ها",
empty: "هنوز اعلانی وجود ندارد.",
loading: "در حال بارگذاری اعلان‌ها...",
loadingMore: "در حال بارگذاری بیشتر...",
loadMore: "بارگذاری بیشتر",
markAllRead: "خواندن همه",
markSeenError: "به‌روزرسانی اعلان با خطا مواجه شد.",
markAllError: "به‌روزرسانی اعلان‌ها با خطا مواجه شد.",
deleteError: "حذف اعلان با خطا مواجه شد.",
loadError: "دریافت اعلان‌ها با خطا مواجه شد.",
newTitle: "اعلان جدید",
openAction: "باز کردن",
summary: (total: number, unread: number) => `${total} کل، ${unread} خوانده‌نشده`,
},
}
noWorkspaceMembers: "عضوی یافت نشد.",
},
tags: {
title: "تگ‌ها",
description: (workspaceName: string) => `مدیریت تگ‌ها برای ${workspaceName}`,
create: "ایجاد تگ",
createTitle: "ایجاد تگ",
editTitle: "ویرایش تگ",
deleteTitle: "حذف تگ",
deleteConfirmMessage: (name: string) => `آیا از حذف ${name} اطمینان دارید؟`,
searchPlaceholder: "جست‌وجوی تگ‌ها...",
nameLabel: "نام تگ",
namePlaceholder: "مثلاً طراحی",
colorLabel: "رنگ",
emptyState: "تگی یافت نشد",
selectWorkspace: "لطفاً ابتدا یک ورک‌اسپیس انتخاب کنید.",
fetchError: "دریافت تگ‌ها با خطا مواجه شد.",
createSuccess: "تگ با موفقیت ایجاد شد.",
updateSuccess: "تگ با موفقیت به‌روزرسانی شد.",
saveError: "ذخیره تگ با خطا مواجه شد.",
deleteSuccess: "تگ با موفقیت حذف شد.",
deleteError: "حذف تگ با خطا مواجه شد.",
},
rates: {
workspaceSectionTitle: "نرخ‌های کاربران ورک‌اسپیس",
projectSectionTitle: "نرخ‌های کاربران پروژه",
workspaceRate: "دستمزد ساعتی",
projectOverride: "نرخ اختصاصی پروژه",
inheritsWorkspaceRate: "ارث‌بری از دستمزد ساعتی",
noRate: "بدون نرخ",
hourlyRatePlaceholder: "0.00",
currencyPlaceholder: "USD",
searchUnitPlaceholder: "جست‌وجوی واحد...",
removeRate: "حذف نرخ",
workspaceSaveSuccess: "نرخ کاربر ورک‌اسپیس ذخیره شد.",
workspaceSaveError: "ذخیره نرخ کاربر ورک‌اسپیس با خطا مواجه شد.",
workspaceRemoveSuccess: "نرخ کاربر ورک‌اسپیس حذف شد.",
workspaceRemoveError: "حذف نرخ کاربر ورک‌اسپیس با خطا مواجه شد.",
projectSaveSuccess: "نرخ کاربر پروژه ذخیره شد.",
projectSaveError: "ذخیره نرخ کاربر پروژه با خطا مواجه شد.",
projectRemoveSuccess: "نرخ کاربر پروژه حذف شد.",
projectRemoveError: "حذف نرخ کاربر پروژه با خطا مواجه شد.",
},
timesheet: {
title: "تایم‌شیت",
description: (workspaceName: string) => `ثبت زمان در ${workspaceName}`,
selectWorkspace: "لطفاً ابتدا یک ورک‌اسپیس انتخاب کنید.",
addEntry: "افزودن ورودی",
startTimer: "شروع تایمر",
stopTimer: "توقف تایمر",
timerRunning: "تایمر فعال است",
runningLabel: ایمر فعلی",
runningBadge: "در حال اجرا",
noRunningEntry: "تایمر فعالی وجود ندارد",
searchPlaceholder: "جست‌وجوی ورودی‌های زمان...",
orderingNewest: "جدیدترین",
orderingOldest: "قدیمی‌ترین",
emptyState: "ورودی زمانی یافت نشد",
emptyDescription: "بدون توضیح",
createTitle: "افزودن ورودی زمان",
startTitle: "شروع تایمر",
editTitle: "ویرایش ورودی زمان",
createSuccess: "ورودی زمان با موفقیت ایجاد شد.",
startSuccess: "تایمر با موفقیت شروع شد.",
updateSuccess: "ورودی زمان با موفقیت به‌روزرسانی شد.",
saveError: "ذخیره ورودی زمان با خطا مواجه شد.",
stopSuccess: "تایمر با موفقیت متوقف شد.",
stopError: "توقف تایمر با خطا مواجه شد.",
deleteSuccess: "ورودی زمان با موفقیت حذف شد.",
deleteError: "حذف ورودی زمان با خطا مواجه شد.",
fetchError: "دریافت ورودی‌های زمان با خطا مواجه شد.",
optionsError: "دریافت پروژه‌ها و تگ‌ها با خطا مواجه شد.",
descriptionLabel: وضیحات",
descriptionPlaceholder: "روی چه چیزی کار می‌کنید؟",
projectLabel: "پروژه",
noProject: "بدون پروژه",
startLabel: "شروع",
endLabel: "پایان",
billable: "قابل صورتحساب",
noTagsHint: "ابتدا از صفحه تگ‌ها، تگ ایجاد کنید.",
clearFilters: "پاک کردن فیلترها",
customFromLabel: "از تاریخ",
customToLabel: "تا تاریخ",
allClientsLabel: "همه مشتری‌ها",
allProjectsLabel: "همه پروژه‌ها",
allTagsLabel: "همه تگ‌ها",
showFiltersLabel: "نمایش فیلترها",
hideFiltersLabel: "مخفی کردن فیلترها",
applyFiltersLabel: "اعمال",
clientFilterPrefix: "مشتری",
projectFilterPrefix: "پروژه",
tagFilterPrefix: "تگ",
fromFilterPrefix: "از",
toFilterPrefix: "تا",
},
notifications: {
title: "اعلان‌ها",
open: "باز کردن اعلان‌ها",
empty: "هنوز اعلانی وجود ندارد.",
loading: "در حال بارگذاری اعلان‌ها...",
loadingMore: "در حال بارگذاری بیشتر...",
loadMore: "بارگذاری بیشتر",
markAllRead: "خواندن همه",
markSeenError: "به‌روزرسانی اعلان با خطا مواجه شد.",
markAllError: "به‌روزرسانی اعلان‌ها با خطا مواجه شد.",
deleteError: "حذف اعلان با خطا مواجه شد.",
loadError: "دریافت اعلان‌ها با خطا مواجه شد.",
newTitle: "اعلان جدید",
openAction: "باز کردن",
summary: (total: number, unread: number) => `${total} کل، ${unread} خوانده‌نشده`,
},
}