Rename store items to store products and add an empty-state CTA.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
8e8929050e
commit
9a59bc8f65
@@ -662,7 +662,8 @@ const en = {
|
||||
'storeItems.search': 'Search',
|
||||
'storeItems.clearFilters': 'Clear filters',
|
||||
'storeItems.loading': 'Loading store items...',
|
||||
'storeItems.empty': 'No store items yet. Use the + button to add products from your catalog.',
|
||||
'storeItems.empty': "You don't have any products for sale yet.",
|
||||
'storeItems.emptyHint': 'Add products from your catalog to start selling.',
|
||||
'storeItems.emptyFiltered': 'No store items match your filters.',
|
||||
'storeItems.pagination':
|
||||
'Page {page} / {totalPages} · {perPage} per page · {total} total',
|
||||
@@ -1471,11 +1472,17 @@ const en = {
|
||||
'website.ePayment.gateway.digipay': 'DigiPay',
|
||||
'website.ePayment.gateway.digipayDesc': 'DigiPay checkout — coming soon.',
|
||||
'website.ePayment.gateway.zarinpal': 'Zarinpal',
|
||||
'website.ePayment.gateway.zarinpalDesc': 'Zarinpal gateway — coming soon.',
|
||||
'website.ePayment.gateway.zarinpalDesc':
|
||||
'Enter your Merchant ID from the ZarinPal panel. Customers can choose ZarinPal or Mellat at checkout when both are enabled.',
|
||||
'website.ePayment.comingSoon': 'Coming soon',
|
||||
'website.ePayment.terminalId': 'Terminal ID',
|
||||
'website.ePayment.username': 'Username',
|
||||
'website.ePayment.password': 'Password',
|
||||
'website.ePayment.merchantId': 'Merchant ID',
|
||||
'website.ePayment.merchantIdPlaceholder': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
|
||||
'website.ePayment.sandbox': 'Sandbox mode',
|
||||
'website.ePayment.sandboxDesc':
|
||||
'Use ZarinPal sandbox endpoints for testing. Turn off for live payments.',
|
||||
'website.ePayment.passwordSet': 'saved',
|
||||
'website.ePayment.passwordPlaceholder': 'Enter gateway password',
|
||||
'website.ePayment.passwordPlaceholderSet': 'Leave blank to keep current password',
|
||||
@@ -1484,6 +1491,7 @@ const en = {
|
||||
'website.ePayment.saveCredentials': 'Save credentials',
|
||||
'website.ePayment.error.credentials': 'Terminal ID and username are required when Mellat is enabled.',
|
||||
'website.ePayment.error.passwordRequired': 'Password is required the first time you enable Mellat.',
|
||||
'website.ePayment.error.zarinpalMerchant': 'Merchant ID is required when ZarinPal is enabled.',
|
||||
|
||||
'title.signIn': 'Sign in',
|
||||
'title.home': 'Home',
|
||||
@@ -1859,7 +1867,7 @@ const fa: Record<MessageKey, string> = {
|
||||
'nav.products.settings': 'تنظیمات',
|
||||
'nav.store': 'فروشگاه',
|
||||
'nav.store.overview': 'نمای کلی',
|
||||
'nav.store.items': 'اقلام فروشگاه',
|
||||
'nav.store.items': 'محصولات فروشگاه',
|
||||
'nav.store.orders': 'سفارشهای من',
|
||||
'nav.store.shipping': 'هزینه ارسال',
|
||||
'nav.store.cards': 'کارتهای خرید',
|
||||
@@ -2474,9 +2482,9 @@ const fa: Record<MessageKey, string> = {
|
||||
'productSettings.reviewsAutoDesc':
|
||||
'بررسیهای کارشناسی جدید بلافاصله پس از ثبت منتشر میشوند. در صورت نیاز بعداً میتوانید آنها را رد کنید.',
|
||||
|
||||
'store.page.subtitle': 'اقلام، سفارشها و تنظیمات فروشگاه را مدیریت کنید.',
|
||||
'store.card.items.desc': 'همه اقلام فهرستشده در فروشگاه را ببینید و مدیریت کنید.',
|
||||
'store.card.items.link': 'مشاهده اقلام',
|
||||
'store.page.subtitle': 'محصولات، سفارشها و تنظیمات فروشگاه را مدیریت کنید.',
|
||||
'store.card.items.desc': 'همه محصولات فهرستشده در فروشگاه را ببینید و مدیریت کنید.',
|
||||
'store.card.items.link': 'مشاهده محصولات',
|
||||
'store.card.orders.desc': 'سفارشهای مشتریان و ارسال را پیگیری و مدیریت کنید.',
|
||||
'store.card.orders.link': 'مشاهده سفارشها',
|
||||
'store.card.shipping.desc': 'نرخها، مناطق و گزینههای ارسال را پیکربندی کنید.',
|
||||
@@ -2495,14 +2503,15 @@ const fa: Record<MessageKey, string> = {
|
||||
'storeItems.onlyDiscounted': 'فقط تخفیفدار',
|
||||
'storeItems.search': 'جستجو',
|
||||
'storeItems.clearFilters': 'پاک کردن فیلترها',
|
||||
'storeItems.loading': 'در حال بارگذاری اقلام فروشگاه...',
|
||||
'storeItems.empty': 'هنوز قلمی در فروشگاه نیست. با دکمه + از کاتالوگ اضافه کنید.',
|
||||
'storeItems.emptyFiltered': 'هیچ قلمی با فیلترهای شما مطابقت ندارد.',
|
||||
'storeItems.loading': 'در حال بارگذاری محصولات فروشگاه...',
|
||||
'storeItems.empty': 'هنوز هیچ محصولی برای فروش ندارید',
|
||||
'storeItems.emptyHint': 'از کاتالوگ محصول اضافه کنید.',
|
||||
'storeItems.emptyFiltered': 'هیچ محصولی با فیلترهای شما مطابقت ندارد.',
|
||||
'storeItems.pagination':
|
||||
'صفحه {page} / {totalPages} · {perPage} در هر صفحه · {total} مجموع',
|
||||
'storeItems.errorLoad': 'بارگذاری اقلام فروشگاه ممکن نشد.',
|
||||
'storeItems.errorRemove': 'حذف قلم از فروشگاه ممکن نشد.',
|
||||
'storeItems.add': 'افزودن اقلام فروشگاه',
|
||||
'storeItems.errorLoad': 'بارگذاری محصولات فروشگاه ممکن نشد.',
|
||||
'storeItems.errorRemove': 'حذف محصول از فروشگاه ممکن نشد.',
|
||||
'storeItems.add': 'افزودن محصول به فروشگاه',
|
||||
'storeItems.cartOpen': 'باز کردن سبد خرید، {count} قلم',
|
||||
'storeItems.cartOne': 'قلم در سبد',
|
||||
'storeItems.cartMany': 'قلم در سبد',
|
||||
@@ -2521,7 +2530,7 @@ const fa: Record<MessageKey, string> = {
|
||||
'storeItems.card.addToCart': 'افزودن به سبد خرید',
|
||||
'storeItems.pick.title': 'انتخاب تنوع',
|
||||
'storeItems.pick.inStock': '{count} موجود',
|
||||
'storeItems.create.title': 'افزودن اقلام فروشگاه',
|
||||
'storeItems.create.title': 'افزودن محصول به فروشگاه',
|
||||
'storeItems.create.subtitle': 'تنوعهای قابل فروش را از تنوعهای یک محصول بسازید.',
|
||||
'storeItems.create.productPlaceholder': 'محصول — حداقل ۳ کاراکتر برای جستجو',
|
||||
'storeItems.create.loadingVariations': 'در حال بارگذاری تنوعهای محصول...',
|
||||
@@ -2533,7 +2542,7 @@ const fa: Record<MessageKey, string> = {
|
||||
'storeItems.create.addAllProducts': 'افزودن همه محصولات',
|
||||
'storeItems.create.addingAll': 'در حال ایجاد برای همه محصولات…',
|
||||
'storeItems.create.addAllDone': 'ایجاد شد {created}، رد شد {skipped}، ناموفق {failed}',
|
||||
'storeItems.create.addAllConfirmTitle': 'افزودن اقلام برای همه محصولات؟',
|
||||
'storeItems.create.addAllConfirmTitle': 'افزودن همه محصولات به فروشگاه؟',
|
||||
'storeItems.create.addAllConfirmIntro':
|
||||
'برای هر محصولی که هنوز به فروشگاه اضافه نشده است، تنوعهای قابل فروش ساخته میشود. فقط وقتی میخواهید همهٔ محصولات یکجا به فروشگاه اضافه شود از این گزینه استفاده کنید.',
|
||||
'storeItems.create.addAllConfirmMax':
|
||||
@@ -2547,16 +2556,16 @@ const fa: Record<MessageKey, string> = {
|
||||
'storeItems.create.addAllResultTitle': 'ایجاد گروهی تمام شد',
|
||||
'storeItems.create.addAllDoneBtn': 'باشه',
|
||||
'storeItems.create.cancel': 'انصراف',
|
||||
'storeItems.create.submit': 'ایجاد اقلام فروشگاه',
|
||||
'storeItems.create.submitting': 'در حال ایجاد…',
|
||||
'storeItems.create.submit': 'افزودن محصول به فروشگاه',
|
||||
'storeItems.create.submitting': 'در حال افزودن…',
|
||||
'storeItems.create.errorProducts': 'بارگذاری محصولات ممکن نشد.',
|
||||
'storeItems.create.errorVariations': 'بارگذاری تنوعهای محصول ممکن نشد.',
|
||||
'storeItems.create.errorCreate': 'ایجاد اقلام فروشگاه ممکن نشد.',
|
||||
'storeItems.create.errorCreate': 'افزودن محصول به فروشگاه ممکن نشد.',
|
||||
'storeItems.price.contact': 'برای قیمت، تماس بگیرید',
|
||||
'storeItems.edit.title': 'ویرایش محصول فروشگاه',
|
||||
'storeItems.edit.save': 'ذخیره تغییرات',
|
||||
'storeItems.edit.saving': 'در حال ذخیره…',
|
||||
'storeItems.edit.errorSave': 'ذخیره اقلام فروشگاه ممکن نشد.',
|
||||
'storeItems.edit.errorSave': 'ذخیره محصول فروشگاه ممکن نشد.',
|
||||
'storeItems.search.clear': 'پاک کردن انتخاب',
|
||||
'storeItems.search.noProducts': 'محصولی موجود نیست.',
|
||||
'storeItems.search.noMatch': 'محصولی یافت نشد.',
|
||||
@@ -3303,11 +3312,17 @@ const fa: Record<MessageKey, string> = {
|
||||
'website.ePayment.gateway.digipay': 'دیجیپی',
|
||||
'website.ePayment.gateway.digipayDesc': 'پرداخت دیجیپی — بهزودی.',
|
||||
'website.ePayment.gateway.zarinpal': 'زرینپال',
|
||||
'website.ePayment.gateway.zarinpalDesc': 'درگاه زرینپال — بهزودی.',
|
||||
'website.ePayment.gateway.zarinpalDesc':
|
||||
'کد درگاه (Merchant ID) را از پنل زرینپال وارد کنید. اگر ملت و زرینپال هر دو فعال باشند، مشتری در مرحله پرداخت یکی را انتخاب میکند.',
|
||||
'website.ePayment.comingSoon': 'بهزودی',
|
||||
'website.ePayment.terminalId': 'شناسه ترمینال',
|
||||
'website.ePayment.username': 'نام کاربری',
|
||||
'website.ePayment.password': 'رمز عبور',
|
||||
'website.ePayment.merchantId': 'کد درگاه (Merchant ID)',
|
||||
'website.ePayment.merchantIdPlaceholder': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
|
||||
'website.ePayment.sandbox': 'حالت آزمایشی (Sandbox)',
|
||||
'website.ePayment.sandboxDesc':
|
||||
'برای تست از محیط سندباکس زرینپال استفاده میشود. برای پرداخت واقعی خاموش کنید.',
|
||||
'website.ePayment.passwordSet': 'ذخیرهشده',
|
||||
'website.ePayment.passwordPlaceholder': 'رمز عبور درگاه را وارد کنید',
|
||||
'website.ePayment.passwordPlaceholderSet': 'برای حفظ رمز فعلی خالی بگذارید',
|
||||
@@ -3318,6 +3333,8 @@ const fa: Record<MessageKey, string> = {
|
||||
'با فعال بودن ملت، شناسه ترمینال و نام کاربری الزامی است.',
|
||||
'website.ePayment.error.passwordRequired':
|
||||
'برای اولین بار فعالسازی ملت، رمز عبور الزامی است.',
|
||||
'website.ePayment.error.zarinpalMerchant':
|
||||
'با فعال بودن زرینپال، کد درگاه (Merchant ID) الزامی است.',
|
||||
|
||||
'title.signIn': 'ورود',
|
||||
'title.home': 'خانه',
|
||||
@@ -3332,7 +3349,7 @@ const fa: Record<MessageKey, string> = {
|
||||
'title.brands': 'برندها',
|
||||
'title.settings': 'تنظیمات',
|
||||
'title.store': 'فروشگاه',
|
||||
'title.storeItems': 'اقلام فروشگاه',
|
||||
'title.storeItems': 'محصولات فروشگاه',
|
||||
'title.orders': 'سفارشهای من',
|
||||
'title.shoppingCards': 'کارتهای خرید',
|
||||
'title.customers': 'کاربران',
|
||||
|
||||
@@ -14,6 +14,82 @@
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.emptyState {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
padding: 56px 28px;
|
||||
text-align: center;
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(18px);
|
||||
-webkit-backdrop-filter: blur(18px);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--glass-shadow);
|
||||
}
|
||||
|
||||
.emptyIcon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 6px;
|
||||
border-radius: 16px;
|
||||
color: var(--primary);
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(255, 255, 255, 0.72) 0%,
|
||||
rgba(var(--primary-rgb) / 0.12) 100%
|
||||
);
|
||||
border: 1px solid rgba(255, 255, 255, 0.45);
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
|
||||
.emptyTitle {
|
||||
margin: 0;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.emptyHint {
|
||||
margin: 0 0 8px;
|
||||
max-width: 360px;
|
||||
font-size: 13px;
|
||||
line-height: 1.65;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.emptyCta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
min-height: 42px;
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 8px 20px rgba(var(--primary-rgb) / 0.32);
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
button.emptyCta {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.emptyCta:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 12px 26px rgba(var(--primary-rgb) / 0.4);
|
||||
}
|
||||
|
||||
.error {
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 14px;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { Plus, RotateCcw, Search } from 'lucide-react'
|
||||
import { Package, Plus, RotateCcw, Search } from 'lucide-react'
|
||||
import { Breadcrumbs } from '../components/Breadcrumbs'
|
||||
import { PageTitle } from '../components/PageTitle'
|
||||
import { ConfirmDeleteModal } from '../components/ConfirmDeleteModal'
|
||||
@@ -283,7 +283,7 @@ function StoreItemsPageContent() {
|
||||
|
||||
<div className={pageStyles.pageHeader}>
|
||||
<div>
|
||||
<PageTitle en="STORE ITEMS">{t('title.storeItems')}</PageTitle>
|
||||
<PageTitle en="STORE PRODUCTS">{t('title.storeItems')}</PageTitle>
|
||||
<p className={pageStyles.pageSubtitle}>{t('storeItems.subtitle')}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -370,7 +370,21 @@ function StoreItemsPageContent() {
|
||||
{isLoading ? (
|
||||
<p className={styles.empty}>{t('storeItems.loading')}</p>
|
||||
) : listings.length === 0 ? (
|
||||
<p className={styles.empty}>{t('storeItems.empty')}</p>
|
||||
<div className={styles.emptyState}>
|
||||
<div className={styles.emptyIcon} aria-hidden="true">
|
||||
<Package size={28} strokeWidth={1.75} />
|
||||
</div>
|
||||
<h3 className={styles.emptyTitle}>{t('storeItems.empty')}</h3>
|
||||
<p className={styles.emptyHint}>{t('storeItems.emptyHint')}</p>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.emptyCta}
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus size={18} strokeWidth={2.25} />
|
||||
{t('storeItems.add')}
|
||||
</button>
|
||||
</div>
|
||||
) : filteredListings.length === 0 ? (
|
||||
<p className={styles.empty}>{t('storeItems.emptyFiltered')}</p>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user