2026-02-26 23:09:20 +04:00
|
|
|
export interface Translations {
|
|
|
|
|
header: {
|
|
|
|
|
home: string;
|
|
|
|
|
search: string;
|
|
|
|
|
about: string;
|
|
|
|
|
contacts: string;
|
|
|
|
|
searchPlaceholder: string;
|
|
|
|
|
catalog: string;
|
2026-07-09 01:13:54 +04:00
|
|
|
wishlist: string;
|
|
|
|
|
compare: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
openMenu: string;
|
|
|
|
|
closeMenu: string;
|
feat: close stub-page gaps - profile login/logout, admin Reports/Settings, Help/Docs links
Sprint A: storefront header profile control (login/logout only, no menu),
wired to existing customer Telegram auth (AuthService).
Sprint B: backoffice/reports page, reuses AdminAnalyticsFacade (Sales,
Top Products, Marketplace Health cards + CSV export).
Sprint C: backoffice/settings page, admin UI density preference
(comfortable/compact), localStorage-persisted, applied to app-table
across all admin list pages.
Sprint D: admin bottom-nav Help -> mailto using existing supportEmail,
Documentation -> external link via new TenantConfig.documentationUrl.
AdminNavLink gains externalHref for non-routerLink nav entries.
Docs: docs/GLOBAL-SPRINT-PLAN.md tracks the full sprint breakdown.
docs/COMING-SOON-AUDIT.md removed, folded into docs/KNOWN-ISSUES.md.
docs/BACKEND.md updated with the new documentationUrl bootstrap field.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 17:48:50 +04:00
|
|
|
login: string;
|
|
|
|
|
logout: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
};
|
|
|
|
|
footer: {
|
|
|
|
|
description: string;
|
|
|
|
|
company: string;
|
|
|
|
|
aboutUs: string;
|
|
|
|
|
contacts: string;
|
|
|
|
|
requisites: string;
|
|
|
|
|
support: string;
|
|
|
|
|
faq: string;
|
|
|
|
|
delivery: string;
|
|
|
|
|
guarantee: string;
|
|
|
|
|
legal: string;
|
|
|
|
|
offer: string;
|
|
|
|
|
privacy: string;
|
|
|
|
|
returns: string;
|
|
|
|
|
info: string;
|
|
|
|
|
aboutCompany: string;
|
|
|
|
|
documents: string;
|
|
|
|
|
paymentRules: string;
|
|
|
|
|
returnPolicy: string;
|
|
|
|
|
publicOffer: string;
|
|
|
|
|
help: string;
|
|
|
|
|
payment: string;
|
|
|
|
|
allRightsReserved: string;
|
|
|
|
|
};
|
|
|
|
|
home: {
|
|
|
|
|
welcomeTo: string;
|
|
|
|
|
subtitle: string;
|
|
|
|
|
startSearch: string;
|
|
|
|
|
loading: string;
|
|
|
|
|
errorTitle: string;
|
|
|
|
|
retry: string;
|
|
|
|
|
categoriesTitle: string;
|
|
|
|
|
categoriesSubtitle: string;
|
|
|
|
|
categoriesEmpty: string;
|
|
|
|
|
categoriesEmptyDesc: string;
|
|
|
|
|
dexarHeroTitle: string;
|
|
|
|
|
dexarHeroSubtitle: string;
|
|
|
|
|
dexarHeroTagline: string;
|
|
|
|
|
goToCatalog: string;
|
|
|
|
|
findProduct: string;
|
|
|
|
|
loadingDexar: string;
|
|
|
|
|
catalogTitle: string;
|
|
|
|
|
emptyCategoriesDexar: string;
|
|
|
|
|
categoriesSoonDexar: string;
|
|
|
|
|
itemsCount: string;
|
|
|
|
|
};
|
|
|
|
|
cart: {
|
|
|
|
|
title: string;
|
|
|
|
|
clear: string;
|
|
|
|
|
empty: string;
|
|
|
|
|
emptyDesc: string;
|
|
|
|
|
goShopping: string;
|
|
|
|
|
total: string;
|
|
|
|
|
items: string;
|
|
|
|
|
deliveryLabel: string;
|
2026-06-21 23:13:01 +04:00
|
|
|
deliveryMethod: string;
|
|
|
|
|
selectDelivery: string;
|
|
|
|
|
deliveryPlace: string;
|
|
|
|
|
deliveryTime: string;
|
|
|
|
|
digitalDelivery: string;
|
|
|
|
|
deliveryRequired: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
toPay: string;
|
|
|
|
|
agreeWith: string;
|
|
|
|
|
publicOffer: string;
|
|
|
|
|
returnPolicy: string;
|
|
|
|
|
guaranteeTerms: string;
|
|
|
|
|
privacyPolicy: string;
|
|
|
|
|
and: string;
|
|
|
|
|
checkout: string;
|
2026-06-29 00:06:18 +04:00
|
|
|
payViaQr: string;
|
|
|
|
|
payViaCard: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
close: string;
|
|
|
|
|
creatingPayment: string;
|
|
|
|
|
waitFewSeconds: string;
|
|
|
|
|
scanQr: string;
|
|
|
|
|
amountToPay: string;
|
|
|
|
|
waitingPayment: string;
|
|
|
|
|
copied: string;
|
|
|
|
|
copyLink: string;
|
|
|
|
|
openNewTab: string;
|
|
|
|
|
paymentSuccess: string;
|
|
|
|
|
paymentSuccessDesc: string;
|
|
|
|
|
sending: string;
|
|
|
|
|
send: string;
|
2026-06-02 00:57:36 +04:00
|
|
|
paymentError: string;
|
|
|
|
|
paymentErrorDesc: string;
|
|
|
|
|
retryPayment: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
paymentTimeout: string;
|
|
|
|
|
paymentTimeoutDesc: string;
|
|
|
|
|
autoClose: string;
|
|
|
|
|
confirmClear: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
removeItem: string;
|
2026-07-19 23:39:14 +04:00
|
|
|
increaseQuantity: string;
|
|
|
|
|
decreaseQuantity: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
paymentQrAlt: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
acceptTerms: string;
|
|
|
|
|
copyError: string;
|
|
|
|
|
emailSuccess: string;
|
|
|
|
|
emailError: string;
|
|
|
|
|
phoneRequired: string;
|
|
|
|
|
phoneMoreDigits: string;
|
|
|
|
|
phoneTooMany: string;
|
|
|
|
|
emailRequired: string;
|
|
|
|
|
emailTooShort: string;
|
|
|
|
|
emailTooLong: string;
|
|
|
|
|
emailNeedsAt: string;
|
|
|
|
|
emailNeedsDomain: string;
|
|
|
|
|
emailInvalid: string;
|
2026-03-24 00:09:11 +04:00
|
|
|
loginRequired: string;
|
|
|
|
|
loginRequiredDesc: string;
|
|
|
|
|
loginWithTelegram: string;
|
|
|
|
|
orScanQr: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
};
|
|
|
|
|
search: {
|
|
|
|
|
title: string;
|
|
|
|
|
placeholder: string;
|
2026-07-10 13:25:31 +04:00
|
|
|
searchBarAria: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
resultsCount: string;
|
|
|
|
|
searching: string;
|
|
|
|
|
retry: string;
|
|
|
|
|
noResults: string;
|
|
|
|
|
noResultsFor: string;
|
|
|
|
|
noResultsHint: string;
|
2026-07-10 13:25:31 +04:00
|
|
|
emptyResultsAria: string;
|
|
|
|
|
popularCategories: string;
|
|
|
|
|
recommendedProducts: string;
|
|
|
|
|
aiSuggestionHint: string;
|
|
|
|
|
suggestionType: {
|
|
|
|
|
product: string;
|
|
|
|
|
category: string;
|
|
|
|
|
brand: string;
|
|
|
|
|
collection: string;
|
|
|
|
|
seller: string;
|
|
|
|
|
'static-page': string;
|
|
|
|
|
ai: string;
|
|
|
|
|
};
|
2026-02-26 23:09:20 +04:00
|
|
|
addToCart: string;
|
|
|
|
|
loadingMore: string;
|
|
|
|
|
allLoaded: string;
|
|
|
|
|
emptyState: string;
|
2026-07-05 01:10:56 +04:00
|
|
|
minLength: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
of: string;
|
|
|
|
|
};
|
|
|
|
|
category: {
|
|
|
|
|
retry: string;
|
|
|
|
|
addToCart: string;
|
|
|
|
|
loadingMore: string;
|
|
|
|
|
allLoaded: string;
|
|
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyDesc: string;
|
|
|
|
|
goHome: string;
|
|
|
|
|
loading: string;
|
|
|
|
|
};
|
2026-07-05 01:36:21 +04:00
|
|
|
catalog: {
|
|
|
|
|
title: string;
|
|
|
|
|
breadcrumb: string;
|
|
|
|
|
allCategories: string;
|
|
|
|
|
products: string;
|
|
|
|
|
loading: string;
|
|
|
|
|
loadingProducts: string;
|
|
|
|
|
errorTitle: string;
|
|
|
|
|
error: string;
|
|
|
|
|
retry: string;
|
|
|
|
|
categoryHint: string;
|
|
|
|
|
productHint: string;
|
|
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyCategories: string;
|
|
|
|
|
emptyProducts: string;
|
|
|
|
|
addToCart: string;
|
|
|
|
|
categoriesCount: string;
|
|
|
|
|
productsCount: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
entriesCount: string;
|
|
|
|
|
categoryBannerPlaceholder: string;
|
|
|
|
|
navigationPlaceholder: string;
|
|
|
|
|
removeSavedSearch: string;
|
|
|
|
|
resetFilters: string;
|
|
|
|
|
filtersTitle: string;
|
2026-07-09 02:57:48 +04:00
|
|
|
from: string;
|
|
|
|
|
to: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
minValue: string;
|
|
|
|
|
maxValue: string;
|
|
|
|
|
enabled: string;
|
|
|
|
|
searchPlaceholder: string;
|
|
|
|
|
searchSubmit: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
clearSearch: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
suggestionsTitle: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
popularSearchesTitle: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
recentSearchesTitle: string;
|
|
|
|
|
searchHistoryTitle: string;
|
|
|
|
|
clearHistory: string;
|
|
|
|
|
searchNoResultsHint: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
searchProductsFound: string;
|
|
|
|
|
searchResultsSummary: string;
|
2026-07-10 15:55:38 +04:00
|
|
|
loadMore: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
sortBy: string;
|
|
|
|
|
sortRelevance: string;
|
|
|
|
|
sortLatest: string;
|
|
|
|
|
sortPriceAsc: string;
|
|
|
|
|
sortPriceDesc: string;
|
|
|
|
|
sortRating: string;
|
|
|
|
|
sortPopular: string;
|
|
|
|
|
sortDiscount: string;
|
|
|
|
|
layoutGrid: string;
|
|
|
|
|
layoutLargeGrid: string;
|
|
|
|
|
layoutCompactGrid: string;
|
2026-07-10 15:55:38 +04:00
|
|
|
layoutGrid2: string;
|
|
|
|
|
layoutGrid3: string;
|
|
|
|
|
layoutGrid4: string;
|
|
|
|
|
layoutCompact: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
layoutList: string;
|
|
|
|
|
noResults: string;
|
|
|
|
|
itemsCount: string;
|
|
|
|
|
emptyResultsTitle: string;
|
|
|
|
|
emptyResultsDescription: string;
|
|
|
|
|
previousPage: string;
|
|
|
|
|
nextPage: string;
|
|
|
|
|
pageOf: string;
|
2026-07-09 01:46:32 +04:00
|
|
|
emptyCategoryTitle: string;
|
|
|
|
|
emptyCategoryMessage: string;
|
2026-07-10 15:55:38 +04:00
|
|
|
goToParentCategory: string;
|
2026-07-09 01:46:32 +04:00
|
|
|
browseCategories: string;
|
2026-07-10 15:55:38 +04:00
|
|
|
offlineTitle: string;
|
|
|
|
|
offlineMessage: string;
|
2026-07-09 01:46:32 +04:00
|
|
|
noFilterMatchTitle: string;
|
|
|
|
|
noFilterMatchMessage: string;
|
|
|
|
|
clearFilters: string;
|
|
|
|
|
openFilters: string;
|
|
|
|
|
applyFilters: string;
|
|
|
|
|
close: string;
|
|
|
|
|
filtersDrawerAria: string;
|
|
|
|
|
sortSheetAria: string;
|
|
|
|
|
mobileToolbarAria: string;
|
|
|
|
|
gridCycle: string;
|
|
|
|
|
filtersPanelAria: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
filterPrice: string;
|
|
|
|
|
filterAvailability: string;
|
|
|
|
|
filterInStock: string;
|
|
|
|
|
filterLowStock: string;
|
|
|
|
|
filterOutOfStock: string;
|
|
|
|
|
filterRating: string;
|
|
|
|
|
filterStars: string;
|
|
|
|
|
filterBrand: string;
|
|
|
|
|
filterCategory: string;
|
|
|
|
|
filterCategoryValue: string;
|
|
|
|
|
filterSubcategory: string;
|
|
|
|
|
filterDiscount: string;
|
|
|
|
|
filterNew: string;
|
|
|
|
|
filterColor: string;
|
|
|
|
|
filterSize: string;
|
|
|
|
|
filterAttributes: string;
|
2026-07-19 22:04:13 +04:00
|
|
|
favorite: string;
|
|
|
|
|
compare: string;
|
|
|
|
|
share: string;
|
|
|
|
|
quickView: string;
|
|
|
|
|
stockHigh: string;
|
|
|
|
|
stockMedium: string;
|
|
|
|
|
stockLow: string;
|
|
|
|
|
stockOut: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
};
|
|
|
|
|
productDetails: {
|
|
|
|
|
loading: string;
|
|
|
|
|
errorTitle: string;
|
|
|
|
|
retry: string;
|
|
|
|
|
missingTitle: string;
|
|
|
|
|
missingDescription: string;
|
|
|
|
|
backToCatalog: string;
|
|
|
|
|
tabsAria: string;
|
|
|
|
|
mediaAria: string;
|
|
|
|
|
ratingStarsAria: string;
|
|
|
|
|
selectRatingAria: string;
|
fix(storefront): premium UX polish for product, compare, wishlist
- delivery-information, product-actions, product-description,
product-gallery, product-information, related-products,
variant-selector: normalize hardcoded hex colors to design tokens
(--text-primary, --text-secondary, --border-color, --bg-primary/
--bg-secondary, --primary-color/--primary-hover); stock status and
discount badge now use semantic --success-color/--warning-color/
--error-color instead of near-duplicate literal hex
- product-actions: add aria-pressed to wishlist/compare toggle
buttons; add hover/active/disabled states to action buttons
- product-gallery: add aria-current + aria-label to active thumbnail
button; add focus-visible ring and hover state on thumbnails and
toolbar buttons
- variant-selector: add aria-pressed to colour/size option buttons;
add a visible checkmark glyph on the selected colour swatch so
selection isn't color-only; add hover states
- product-tabs: add role="tab"/aria-selected to tab buttons
- star-selector: add per-star aria-label (new starsLabel i18n key
added to en/hy/ru + translations.ts interface)
- question-list: add aria-expanded to the ask-question disclosure
toggle; swap plain empty-state <p> for app-empty-state; add
hover/disabled states to pager buttons
- review-list: swap plain empty-state <p> for app-empty-state; add
hover/disabled states to pager and load-more buttons
- question-card, question-form, review-form: normalize accepted/
success/error colors to semantic tokens; add focus-visible and
hover/disabled states to inputs and submit buttons
- compare-table: add scope="col"/scope="row" to table headers; make
header row and attribute column sticky for easier comparison on
long tables
- compare-page: add hover/focus states to the remove-from-compare
chip button
Build verified green via `npm run build`.
Out of scope / skipped:
- src/app/pages/item-detail/* is dead code (not referenced by any
route or component) - left untouched
- wishlist page and product-details-container were already fully
composed with shared skeleton/empty-state/button components from
the RC-Visual-02 pass - no changes needed
- stars.component display-only rating glyphs use a light gray not an
exact token match - left as-is to avoid an unintended visual shift
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 11:47:57 +04:00
|
|
|
starsLabel: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
reviewsEmpty: string;
|
|
|
|
|
questionsEmpty: string;
|
|
|
|
|
askQuestion: string;
|
|
|
|
|
hideQuestionForm: string;
|
|
|
|
|
questionFormTitle: string;
|
|
|
|
|
questionFormPlaceholder: string;
|
|
|
|
|
questionFormAnonymous: string;
|
|
|
|
|
submitQuestion: string;
|
|
|
|
|
reviewFormTitle: string;
|
|
|
|
|
reviewRatingLabel: string;
|
|
|
|
|
reviewTitleLabel: string;
|
|
|
|
|
reviewTitlePlaceholder: string;
|
|
|
|
|
reviewTextLabel: string;
|
|
|
|
|
reviewTextPlaceholder: string;
|
|
|
|
|
reviewAnonymous: string;
|
|
|
|
|
reviewUploadPlaceholder: string;
|
2026-07-10 13:10:35 +04:00
|
|
|
reviewRatingRequired: string;
|
|
|
|
|
reviewTextRequired: string;
|
|
|
|
|
reviewSuccess: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
submitReview: string;
|
|
|
|
|
submitting: string;
|
2026-07-10 13:10:35 +04:00
|
|
|
loadMore: string;
|
|
|
|
|
showingOf: string;
|
|
|
|
|
questionsSubmissionFuture: string;
|
|
|
|
|
specificationsGeneral: string;
|
|
|
|
|
actionsAria: string;
|
|
|
|
|
buyNow: string;
|
|
|
|
|
wishlist: string;
|
|
|
|
|
compare: string;
|
|
|
|
|
share: string;
|
|
|
|
|
notifyMe: string;
|
|
|
|
|
zoom: string;
|
|
|
|
|
fullscreen: string;
|
|
|
|
|
pdfDocument: string;
|
|
|
|
|
manualDocument: string;
|
|
|
|
|
warrantyDocument: string;
|
|
|
|
|
openDocument: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
specificationsEmpty: string;
|
|
|
|
|
warrantyTitle: string;
|
|
|
|
|
warrantyItem1: string;
|
|
|
|
|
warrantyItem2: string;
|
|
|
|
|
warrantyItem3: string;
|
|
|
|
|
verifiedPurchase: string;
|
|
|
|
|
officialSeller: string;
|
|
|
|
|
acceptedAnswer: string;
|
|
|
|
|
like: string;
|
|
|
|
|
dislike: string;
|
|
|
|
|
reviewsCountLabel: string;
|
|
|
|
|
previous: string;
|
|
|
|
|
next: string;
|
|
|
|
|
pageOf: string;
|
2026-07-05 01:36:21 +04:00
|
|
|
};
|
2026-02-26 23:09:20 +04:00
|
|
|
subcategories: {
|
|
|
|
|
loading: string;
|
|
|
|
|
retry: string;
|
|
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyDesc: string;
|
|
|
|
|
goHome: string;
|
2026-03-24 00:09:11 +04:00
|
|
|
itemsInCategory: string;
|
2026-07-05 01:09:55 +04:00
|
|
|
childrenCount: string;
|
|
|
|
|
productsCount: string;
|
|
|
|
|
includesProducts: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
};
|
|
|
|
|
itemDetail: {
|
|
|
|
|
loading: string;
|
|
|
|
|
loadingDexar: string;
|
|
|
|
|
back: string;
|
|
|
|
|
backHome: string;
|
|
|
|
|
noImage: string;
|
|
|
|
|
stock: string;
|
|
|
|
|
inStock: string;
|
|
|
|
|
lowStock: string;
|
|
|
|
|
lastItems: string;
|
|
|
|
|
mediumStock: string;
|
|
|
|
|
addToCart: string;
|
|
|
|
|
description: string;
|
2026-02-28 16:13:14 +04:00
|
|
|
specifications: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
reviews: string;
|
|
|
|
|
yourReview: string;
|
|
|
|
|
leaveReview: string;
|
|
|
|
|
rating: string;
|
|
|
|
|
reviewPlaceholder: string;
|
|
|
|
|
reviewPlaceholderDexar: string;
|
|
|
|
|
anonymous: string;
|
|
|
|
|
submitting: string;
|
|
|
|
|
submit: string;
|
|
|
|
|
reviewSuccess: string;
|
|
|
|
|
reviewError: string;
|
|
|
|
|
defaultUser: string;
|
|
|
|
|
defaultUserDexar: string;
|
|
|
|
|
noReviews: string;
|
|
|
|
|
qna: string;
|
|
|
|
|
photo: string;
|
|
|
|
|
reviewsCount: string;
|
|
|
|
|
today: string;
|
|
|
|
|
yesterday: string;
|
|
|
|
|
daysAgo: string;
|
|
|
|
|
weeksAgo: string;
|
2026-03-24 00:09:11 +04:00
|
|
|
colour: string;
|
|
|
|
|
size: string;
|
2026-07-05 01:07:53 +04:00
|
|
|
relatedProducts: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
};
|
|
|
|
|
app: {
|
|
|
|
|
connecting: string;
|
|
|
|
|
serverUnavailable: string;
|
|
|
|
|
serverError: string;
|
|
|
|
|
retryConnection: string;
|
|
|
|
|
pageTitle: string;
|
fix(storefront): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, storefront + shared app-shell chrome only. Builds
on RC-Visual-02/RC-Premium-01/RC STORE-01 without redoing that work.
- Skip link: added first-focusable "skip to main content" link (app.html,
styles.scss .skip-link/.sr-only), targeting new #main-content landmark.
New app.skipToContent i18n key in en/ru/hy.
- Header: mobile menu items stayed keyboard-focusable and screen-reader
reachable while visually collapsed (max-height:0 with no visibility
toggle) - fixed with visibility:hidden + matched transition-delay.
Desktop search input (readonly, click-to-navigate) had no keyboard
activation - added aria-label + (keydown.enter).
- Cart payment/bank-payment modals: custom (non-app-dialog) UI had no
focus trap, no Escape handling, and never returned focus to the
triggering element - ported app-dialog's confirmed-correct
focus-trap/Escape/return-focus pattern directly onto cart.component.ts.
Added role="dialog"/aria-modal/aria-label to both panels and
role="status"|"alert"/aria-live to every payment-status screen so
screen readers announce state changes (creating/waiting/success/
error/timeout).
- Search combobox: suggestion listbox had no role="combobox" wiring on
the input and suggestion buttons weren't role="option" - added
aria-autocomplete, aria-controls, aria-activedescendant, aria-selected
so the existing arrow-key navigation is announced to screen readers.
- Product tabs: tablist/tab pattern was incomplete (no role="tablist",
no tabpanel) - added role="tablist" + ids to product-tabs.component,
role="tabpanel"/aria-labelledby to the content panel in
product-details-container.
- Review form: rating/text validation errors weren't associated with
their controls (no aria-describedby, no role="alert") - fixed; added
aria-required to the review textarea.
- delivery-selector: added aria-required to the delivery <select> when
a selection is mandatory.
- Shared app-icon component: doc comment claimed "decorative by default
(aria-hidden)" but no aria-hidden was ever applied - fixed to actually
set aria-hidden="true" when undecorated, and role="img"/aria-label
when ariaLabel is passed. Shared component, affects every icon-only
usage app-wide, no visual change.
- Color contrast: --text-light fails WCAG AA 4.5:1 for normal text in
every theme (dexar 3.39:1, lavero/novo 2.54:1 against white). The two
in-scope usages (company-details org-short/basis, review-form
upload-placeholder) switched to --text-secondary (4.55:1-7.56:1,
passes), same visual family, no layout change.
Flagged, not fixed (design-system decisions, not polish):
- --border-color fails WCAG 1.4.11 3:1 for UI-component boundaries in
every theme (dexar 1.42:1, lavero/novo 1.24:1 vs white) - pervasive
token used by hundreds of borders app-wide; needs theme-owner sign-off.
- --success-color/--warning-color/--error-color/--info-color used as
plain text-on-white in several places (product-information,
question-card, review-form, compare-page) fail 4.5:1 (2.15-3.76:1) -
genuine brand semantic colors, changing them to pass would visibly
shift the palette; needs a deliberate token decision.
- Header mobile-menu max-height/padding transition (pre-existing,
unrelated to this fix) flagged by design lint as layout-thrashing;
left as-is per the "no layout/business-logic changes" constraint.
Verified: npx tsc --noEmit clean; npm run build green (only the
pre-existing bundle-budget warning, unrelated to this pass).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 08:46:18 +04:00
|
|
|
skipToContent: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
};
|
2026-07-09 02:29:12 +04:00
|
|
|
platform: {
|
|
|
|
|
loadingPage: string;
|
|
|
|
|
emptyConfig: string;
|
|
|
|
|
};
|
|
|
|
|
backoffice: {
|
|
|
|
|
title: string;
|
|
|
|
|
subtitle: string;
|
|
|
|
|
loading: string;
|
|
|
|
|
products: string;
|
|
|
|
|
categories: string;
|
|
|
|
|
otherDomains: string;
|
|
|
|
|
sku: string;
|
|
|
|
|
titleColumn: string;
|
|
|
|
|
price: string;
|
|
|
|
|
status: string;
|
|
|
|
|
itemsCount: string;
|
|
|
|
|
orders: string;
|
|
|
|
|
customers: string;
|
|
|
|
|
inventory: string;
|
|
|
|
|
media: string;
|
|
|
|
|
settings: string;
|
|
|
|
|
notAvailable: string;
|
|
|
|
|
};
|
|
|
|
|
builder: {
|
|
|
|
|
title: string;
|
|
|
|
|
subtitle: string;
|
2026-07-10 13:43:53 +04:00
|
|
|
general: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
branding: string;
|
2026-07-10 13:43:53 +04:00
|
|
|
theme: string;
|
|
|
|
|
header: string;
|
|
|
|
|
footer: string;
|
|
|
|
|
homepage: string;
|
|
|
|
|
widgets: string;
|
2026-07-10 13:52:01 +04:00
|
|
|
staticPages: string;
|
2026-07-10 13:43:53 +04:00
|
|
|
marketplaceFeatures: string;
|
|
|
|
|
preview: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
brandName: string;
|
2026-07-10 13:43:53 +04:00
|
|
|
marketplaceName: string;
|
|
|
|
|
domain: string;
|
|
|
|
|
descriptionLabel: string;
|
|
|
|
|
defaultLanguage: string;
|
|
|
|
|
supportedLanguages: string;
|
|
|
|
|
logo: string;
|
|
|
|
|
smallLogo: string;
|
|
|
|
|
favicon: string;
|
2026-07-17 15:22:45 +04:00
|
|
|
socialImage: string;
|
|
|
|
|
gallery: string;
|
|
|
|
|
addGalleryImage: string;
|
2026-07-17 15:29:55 +04:00
|
|
|
headerLayout: string;
|
|
|
|
|
headerLayoutDefault: string;
|
|
|
|
|
headerLayoutCentered: string;
|
|
|
|
|
headerSticky: string;
|
2026-07-10 13:43:53 +04:00
|
|
|
marketplaceTitle: string;
|
|
|
|
|
primaryColor: string;
|
|
|
|
|
secondaryColor: string;
|
|
|
|
|
backgroundColor: string;
|
|
|
|
|
surfaceColor: string;
|
|
|
|
|
textColor: string;
|
|
|
|
|
successColor: string;
|
|
|
|
|
warningColor: string;
|
|
|
|
|
dangerColor: string;
|
|
|
|
|
showLogo: string;
|
|
|
|
|
showSearch: string;
|
|
|
|
|
showCategories: string;
|
|
|
|
|
showLanguages: string;
|
|
|
|
|
showCart: string;
|
|
|
|
|
showProfile: string;
|
|
|
|
|
showWishlist: string;
|
|
|
|
|
showCompare: string;
|
|
|
|
|
showRegion: string;
|
|
|
|
|
companyName: string;
|
|
|
|
|
address: string;
|
|
|
|
|
phone: string;
|
|
|
|
|
email: string;
|
|
|
|
|
copyright: string;
|
|
|
|
|
paymentIcons: string;
|
|
|
|
|
socialLinks: string;
|
2026-07-16 02:06:26 +04:00
|
|
|
footerLogo: string;
|
|
|
|
|
addPaymentIcon: string;
|
|
|
|
|
removePaymentIcon: string;
|
|
|
|
|
iconAltLabel: string;
|
|
|
|
|
addSocialLink: string;
|
|
|
|
|
removeSocialLink: string;
|
|
|
|
|
socialLinkLabel: string;
|
|
|
|
|
socialLinkUrl: string;
|
|
|
|
|
invalidUrl: string;
|
2026-07-10 13:52:01 +04:00
|
|
|
createPage: string;
|
|
|
|
|
deletePage: string;
|
|
|
|
|
pageId: string;
|
|
|
|
|
slug: string;
|
|
|
|
|
iconLabel: string;
|
|
|
|
|
showInFooter: string;
|
|
|
|
|
showInHeader: string;
|
|
|
|
|
showInSitemap: string;
|
|
|
|
|
requiresAuthentication: string;
|
|
|
|
|
footerGroup: string;
|
|
|
|
|
orderLabel: string;
|
|
|
|
|
translationTitle: string;
|
|
|
|
|
htmlPreview: string;
|
2026-07-15 04:11:18 +04:00
|
|
|
seoSection: string;
|
|
|
|
|
seoTitle: string;
|
|
|
|
|
seoDescription: string;
|
|
|
|
|
seoKeywords: string;
|
|
|
|
|
seoCanonical: string;
|
|
|
|
|
seoOgTitle: string;
|
|
|
|
|
seoOgDescription: string;
|
|
|
|
|
seoOgImage: string;
|
2026-07-10 13:43:53 +04:00
|
|
|
visible: string;
|
|
|
|
|
layoutLabel: string;
|
|
|
|
|
columns: string;
|
|
|
|
|
height: string;
|
|
|
|
|
overlay: string;
|
|
|
|
|
autoplay: string;
|
|
|
|
|
cardsPerRow: string;
|
|
|
|
|
filtersLabel: string;
|
|
|
|
|
showBadges: string;
|
|
|
|
|
showRating: string;
|
|
|
|
|
showPrice: string;
|
|
|
|
|
widgetJson: string;
|
|
|
|
|
reviews: string;
|
|
|
|
|
questions: string;
|
|
|
|
|
comments: string;
|
|
|
|
|
recommendations: string;
|
|
|
|
|
recentlyViewed: string;
|
|
|
|
|
searchSuggestions: string;
|
|
|
|
|
searchHistory: string;
|
|
|
|
|
livePreview: string;
|
2026-07-17 09:00:47 +04:00
|
|
|
previewChangesTitle: string;
|
|
|
|
|
previewNoIssues: string;
|
|
|
|
|
previewNoChanges: string;
|
|
|
|
|
previewChangeField: string;
|
|
|
|
|
previewChangeBefore: string;
|
|
|
|
|
previewChangeAfter: string;
|
2026-07-13 08:10:00 +04:00
|
|
|
languagesTab: string;
|
|
|
|
|
addLanguage: string;
|
|
|
|
|
removeLanguage: string;
|
|
|
|
|
setDefaultLanguage: string;
|
|
|
|
|
defaultLanguageLabel: string;
|
2026-07-13 08:57:42 +04:00
|
|
|
navigationTab: string;
|
|
|
|
|
navigationHeader: string;
|
|
|
|
|
navigationFooter: string;
|
|
|
|
|
navigationFooterGrouped: string;
|
|
|
|
|
addLink: string;
|
2026-07-17 10:18:08 +04:00
|
|
|
insertPageLink: string;
|
|
|
|
|
linkedToPage: string;
|
2026-07-13 08:57:42 +04:00
|
|
|
removeLink: string;
|
|
|
|
|
linkLabel: string;
|
|
|
|
|
linkUrl: string;
|
2026-07-10 13:43:53 +04:00
|
|
|
exportBootstrap: string;
|
|
|
|
|
importBootstrap: string;
|
|
|
|
|
exportedBootstrap: string;
|
|
|
|
|
importSource: string;
|
|
|
|
|
importError: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
featureFlags: string;
|
2026-07-13 10:51:05 +04:00
|
|
|
validationMissingLogo: string;
|
|
|
|
|
validationNoLanguages: string;
|
2026-07-17 19:00:17 +04:00
|
|
|
validationDefaultLocaleNotSupported: string;
|
2026-07-13 10:51:05 +04:00
|
|
|
validationInvalidUrl: string;
|
|
|
|
|
validationDuplicateSlugs: string;
|
|
|
|
|
validationEmptyHomepage: string;
|
|
|
|
|
validationMissingWidget: string;
|
|
|
|
|
validationDuplicateNavLinks: string;
|
|
|
|
|
validationInvalidColors: string;
|
2026-07-14 12:21:33 +04:00
|
|
|
validationMissingTranslations: string;
|
|
|
|
|
validationInvalidLayouts: string;
|
feat(project-editor): centralize schema-driven validation
Milestone 2 of the Configuration Engine sprint.
- Add schema/validators/primitives: pure isValidHexColor/HttpUrl/Email,
validateJson, validateCss, extractStyleBlocks, normalizeRoute. One function
per concern, no duplicated validator logic.
- Refactor ProjectValidator to compose the primitives and tag every issue with
section + fieldKey + severity ('error' blocks publish, 'warning' advisory).
Preserves all existing codes/messages; adds duplicate-routes, invalid-css,
invalid-widget-config checks.
- Facade: issuesByField, issuesBySection, blockingIssues, hasBlockingIssues;
publish() now gates on severity==='error' instead of any issue.
- i18n: add validationInvalidJson/Css/DuplicateRoutes/InvalidWidgetConfig to
the Translations interface + en/ru/hy.
- Specs: primitives + ProjectValidator (25 passing total).
Gate: tsc --noEmit, npm test (25/25), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:58:36 +04:00
|
|
|
validationInvalidJson: string;
|
|
|
|
|
validationInvalidCss: string;
|
|
|
|
|
validationDuplicateRoutes: string;
|
|
|
|
|
validationInvalidWidgetConfig: string;
|
2026-07-17 16:57:43 +04:00
|
|
|
validationInvalidContactEmail: string;
|
|
|
|
|
validationInvalidSocialLinkUrl: string;
|
|
|
|
|
validationIncompletePaymentIcon: string;
|
2026-07-17 02:13:34 +04:00
|
|
|
undo: string;
|
|
|
|
|
redo: string;
|
2026-07-13 15:00:03 +04:00
|
|
|
statusDraft: string;
|
|
|
|
|
statusPublished: string;
|
|
|
|
|
unsavedChanges: string;
|
|
|
|
|
save: string;
|
|
|
|
|
publish: string;
|
2026-07-13 15:57:54 +04:00
|
|
|
confirmLeaveUnsaved: string;
|
2026-07-25 20:43:43 +04:00
|
|
|
confirmPublish: string;
|
|
|
|
|
confirmRemoveLanguage: string;
|
2026-07-13 15:57:54 +04:00
|
|
|
promptLinkUrl: string;
|
|
|
|
|
promptImageUrl: string;
|
2026-07-17 10:00:33 +04:00
|
|
|
promptEmbedUrl: string;
|
|
|
|
|
htmlEditorInvalidHtml: string;
|
2026-07-13 15:57:54 +04:00
|
|
|
htmlEditorCode: string;
|
|
|
|
|
htmlEditorPreview: string;
|
2026-07-14 09:50:03 +04:00
|
|
|
lastSaved: string;
|
|
|
|
|
draftRestored: string;
|
|
|
|
|
dismiss: string;
|
|
|
|
|
resetDraft: string;
|
|
|
|
|
resetSection: string;
|
|
|
|
|
confirmResetDraft: string;
|
|
|
|
|
confirmResetSection: string;
|
2026-07-14 16:05:09 +04:00
|
|
|
marketplaceNameDesc: string;
|
|
|
|
|
domainDesc: string;
|
|
|
|
|
descriptionFieldDesc: string;
|
|
|
|
|
defaultLanguageDesc: string;
|
|
|
|
|
supportedLanguagesDesc: string;
|
|
|
|
|
logoDesc: string;
|
|
|
|
|
smallLogoDesc: string;
|
|
|
|
|
faviconDesc: string;
|
2026-07-17 15:22:45 +04:00
|
|
|
socialImageDesc: string;
|
|
|
|
|
galleryDesc: string;
|
2026-07-17 15:29:55 +04:00
|
|
|
headerLayoutDesc: string;
|
|
|
|
|
headerStickyDesc: string;
|
2026-07-14 16:05:09 +04:00
|
|
|
marketplaceTitleDesc: string;
|
|
|
|
|
primaryColorDesc: string;
|
|
|
|
|
secondaryColorDesc: string;
|
|
|
|
|
backgroundColorDesc: string;
|
|
|
|
|
surfaceColorDesc: string;
|
|
|
|
|
textColorDesc: string;
|
|
|
|
|
successColorDesc: string;
|
|
|
|
|
warningColorDesc: string;
|
|
|
|
|
dangerColorDesc: string;
|
|
|
|
|
themeModeLabel: string;
|
|
|
|
|
themeModeDesc: string;
|
|
|
|
|
themeModeLight: string;
|
|
|
|
|
themeModeLightDesc: string;
|
|
|
|
|
themeModeDark: string;
|
|
|
|
|
themeModeDarkDesc: string;
|
|
|
|
|
themeModeSystem: string;
|
|
|
|
|
themeModeSystemDesc: string;
|
|
|
|
|
siteLayoutLabel: string;
|
|
|
|
|
siteLayoutDesc: string;
|
|
|
|
|
siteLayoutDefault: string;
|
|
|
|
|
siteLayoutDefaultDesc: string;
|
|
|
|
|
siteLayoutSidebarLeft: string;
|
|
|
|
|
siteLayoutSidebarLeftDesc: string;
|
|
|
|
|
siteLayoutCarouselHome: string;
|
|
|
|
|
siteLayoutCarouselHomeDesc: string;
|
|
|
|
|
siteLayoutMinimal: string;
|
|
|
|
|
siteLayoutMinimalDesc: string;
|
|
|
|
|
showLogoDesc: string;
|
|
|
|
|
showSearchDesc: string;
|
|
|
|
|
showCategoriesDesc: string;
|
|
|
|
|
showLanguagesDesc: string;
|
|
|
|
|
showCartDesc: string;
|
|
|
|
|
showProfileDesc: string;
|
|
|
|
|
showWishlistDesc: string;
|
|
|
|
|
showCompareDesc: string;
|
|
|
|
|
showRegionDesc: string;
|
|
|
|
|
companyNameDesc: string;
|
|
|
|
|
addressDesc: string;
|
|
|
|
|
phoneDesc: string;
|
|
|
|
|
emailDesc: string;
|
|
|
|
|
copyrightDesc: string;
|
|
|
|
|
paymentIconsDesc: string;
|
|
|
|
|
socialLinksDesc: string;
|
2026-07-16 02:06:26 +04:00
|
|
|
footerLogoDesc: string;
|
|
|
|
|
iconAltLabelDesc: string;
|
|
|
|
|
socialLinkUrlDesc: string;
|
2026-07-14 16:05:09 +04:00
|
|
|
staticPagesFieldDesc: string;
|
2026-07-19 13:58:57 +04:00
|
|
|
additionalPhones: string;
|
|
|
|
|
additionalPhonesDesc: string;
|
|
|
|
|
addPhone: string;
|
|
|
|
|
removePhone: string;
|
|
|
|
|
additionalEmails: string;
|
|
|
|
|
additionalEmailsDesc: string;
|
|
|
|
|
addEmail: string;
|
|
|
|
|
removeEmail: string;
|
|
|
|
|
footerColumns: string;
|
|
|
|
|
footerColumnsDesc: string;
|
|
|
|
|
footerColumnTitlePlaceholder: string;
|
|
|
|
|
footerLinkLabelPlaceholder: string;
|
|
|
|
|
footerLinkExistingPage: string;
|
|
|
|
|
footerLinkCustomUrl: string;
|
|
|
|
|
addColumn: string;
|
|
|
|
|
removeColumn: string;
|
|
|
|
|
addColumnLink: string;
|
|
|
|
|
removeColumnLink: string;
|
2026-07-14 16:05:09 +04:00
|
|
|
sectionVisibleDesc: string;
|
|
|
|
|
layoutStrategyLabel: string;
|
|
|
|
|
layoutStrategyDesc: string;
|
|
|
|
|
layoutStrategyStack: string;
|
|
|
|
|
layoutStrategyStackDesc: string;
|
|
|
|
|
layoutStrategyGrid: string;
|
|
|
|
|
layoutStrategyGridDesc: string;
|
|
|
|
|
layoutStrategyHero: string;
|
|
|
|
|
layoutStrategyHeroDesc: string;
|
|
|
|
|
layoutStrategyCarousel: string;
|
|
|
|
|
layoutStrategyCarouselDesc: string;
|
|
|
|
|
layoutStrategySplit: string;
|
|
|
|
|
layoutStrategySplitDesc: string;
|
|
|
|
|
sectionColumnsDesc: string;
|
|
|
|
|
widgetLayoutDesc: string;
|
|
|
|
|
widgetHeightDesc: string;
|
|
|
|
|
widgetOverlayDesc: string;
|
|
|
|
|
widgetAutoplayDesc: string;
|
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel.
Homepage section (sections list -> visual blocks):
- Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html
- Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3')
- Added duplicate and remove per block, alongside the existing drag-to-reorder
- Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end
Widgets section (hero widget):
- 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind
- 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values
- New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before
- HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control
Carousel arrows root cause and fix:
- widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place
- Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise
- Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug
New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
|
|
|
heroLayoutFullBleed: string;
|
|
|
|
|
heroLayoutBoxed: string;
|
|
|
|
|
heroHeightCompact: string;
|
|
|
|
|
heroHeightMedium: string;
|
|
|
|
|
heroHeightTall: string;
|
|
|
|
|
heroHeightFullScreen: string;
|
|
|
|
|
heroSlides: string;
|
|
|
|
|
heroSlidesHint: string;
|
|
|
|
|
heroSlideTitlePlaceholder: string;
|
|
|
|
|
heroSlideSubtitlePlaceholder: string;
|
|
|
|
|
addSlide: string;
|
|
|
|
|
removeSlide: string;
|
2026-07-14 16:05:09 +04:00
|
|
|
widgetColumnsDesc: string;
|
|
|
|
|
widgetCardsPerRowDesc: string;
|
|
|
|
|
widgetFiltersDesc: string;
|
|
|
|
|
widgetShowBadgesDesc: string;
|
|
|
|
|
widgetShowRatingDesc: string;
|
|
|
|
|
widgetShowPriceDesc: string;
|
|
|
|
|
widgetJsonDesc: string;
|
2026-07-17 18:14:58 +04:00
|
|
|
widgetJsonInvalid: string;
|
2026-07-14 16:05:09 +04:00
|
|
|
wishlistFeatureDesc: string;
|
|
|
|
|
compareFeatureDesc: string;
|
|
|
|
|
reviewsFeatureDesc: string;
|
|
|
|
|
questionsFeatureDesc: string;
|
|
|
|
|
commentsFeatureDesc: string;
|
|
|
|
|
recommendationsFeatureDesc: string;
|
|
|
|
|
recentlyViewedFeatureDesc: string;
|
|
|
|
|
searchSuggestionsDesc: string;
|
|
|
|
|
searchHistoryDesc: string;
|
|
|
|
|
catalogNavigationModeLabel: string;
|
|
|
|
|
catalogNavigationModeDesc: string;
|
|
|
|
|
catalogNavDefault: string;
|
|
|
|
|
catalogNavDefaultDesc: string;
|
|
|
|
|
catalogNavLeftCategory: string;
|
|
|
|
|
catalogNavLeftCategoryDesc: string;
|
|
|
|
|
catalogNavMegaCategory: string;
|
|
|
|
|
catalogNavMegaCategoryDesc: string;
|
|
|
|
|
catalogNavTopCarousel: string;
|
|
|
|
|
catalogNavTopCarouselDesc: string;
|
fix(builder): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, Builder (project-editor) + content-management static
pages editor. Builds on 4ebc15f's composition pass without redoing it.
- Skip link: Builder's /edit and /edit/:section routes render outside the
storefront app-shell (isAdminRoute() branch has no skip link/landmark, only
a bare router-outlet, unlike the storefront's app.html) - added a
"skip to content" link targeting a new #builder-main-content landmark on
project-editor-page.component, reusing the existing adminShell.skipToContent
key and global .skip-link style. Nav landmark already had aria-label
(builder.appName) from the prior pass, verified correct.
- Save bar: added role="status"/aria-live="polite" to the save/publish status
block and role="status" to the draft-restored notice so save/publish state
changes and draft recovery are announced to screen readers (previously
silent DOM updates).
- Media picker (shared, used by both Builder and static-pages editor): upload
error message had no aria-live wiring - added role="alert".
- HTML editor (marketplace-html-editor): the contenteditable rich-text surface
had no accessible role/name - added role="textbox", aria-multiline="true",
aria-label.
- Drag-and-drop keyboard fallback (WCAG 2.1.1): homepage-section's block list
and footer-section's column list + per-column link list use Angular CDK
drag-drop (cdkDrag/cdkDropList), which has no built-in keyboard reordering.
Added move-up/move-down icon buttons (disabled at the first/last boundary),
matching the existing pattern already used by widgets-section and
navigation-section.
- Color picker: the swatch <input type="color"> had no accessible name (only
the paired text input was labelled via app-form-field) - added explicit
ariaLabel bindings to all 8 color-picker instances in theme-section.
- Languages: the new-locale code input relied on a placeholder ("de") as its
only accessible name - added ariaLabel + new builder.newLanguageLabel i18n
key (en/ru/hy).
- Undefined CSS var --color-primary (never defined anywhere, silently used its
hardcoded hex fallback and never responded to tenant theming - same
recurring bug class as 4ebc15f) - remapped to the real --primary-color token
in marketplace-html-editor, homepage-section, and section.shared (7 usages).
- role="alert" added to all 11 validation-error <p class="editor-error">
occurrences across footer/homepage/languages/navigation/preview/widgets
sections and the static-pages editor, so field/section validation messages
are announced.
- scope="col" added to preview-section's change-summary table headers.
Flagged, not fixed (design-system decisions, matching the storefront pass's
precedent):
- Save bar's --warning-color/--error-color/--info-color text fail WCAG AA
4.5:1 in some themes - same genuine brand semantic colors flagged (not
fixed) in fb1afb7's storefront pass; needs a deliberate token decision,
not a Builder-specific issue.
- locale-tabs (app-locale-tabs, shared) has role="tablist"/"tab" and
aria-selected but no roving-tabindex/arrow-key navigation - matches the
same partial-tablist pattern already accepted for product-tabs in the
storefront pass; all tabs remain natively Tab-focusable, so this meets
4.1.2/2.1.1 without the full ARIA authoring-practice pattern.
Verified: npx tsc --noEmit clean; npm run build green (only the pre-existing
bundle-budget warning, unrelated to this pass).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 09:01:38 +04:00
|
|
|
newLanguageLabel: string;
|
2026-07-14 16:05:09 +04:00
|
|
|
newLanguageDesc: string;
|
2026-07-17 18:31:01 +04:00
|
|
|
languageAlreadyAdded: string;
|
2026-07-14 16:05:09 +04:00
|
|
|
languagesTabDesc: string;
|
|
|
|
|
linkLabelDesc: string;
|
|
|
|
|
linkUrlDesc: string;
|
|
|
|
|
linkVisibleDesc: string;
|
feat(builder): redesign marketplace builder experience and navigation
Renamed the experience consistently to Marketplace Builder everywhere
visible (page title/subtitle, breadcrumbs, sidebar, dashboard quick
action/shortcut copy) - internal ProjectEditor class/selector names
kept as-is to avoid regressions. builder.title/subtitle no longer say
'bootstrap-config editing surface' to end users.
New business-oriented IA (builder-groups.model.ts): 12 existing
ProjectEditorSectionIds regrouped into 8 groups (Marketplace, Branding
and Design, Homepage, Content, Languages, Marketplace Features,
Navigation and Search, Preview) - every existing section mapped to
exactly one group, none dropped, no group points at a page that
doesn't exist.
New Builder landing page at /edit (was a redirect straight into the
General form): readiness percent, recommended next step, one overview
card per group (purpose + real complete/in-progress/not-started/unknown
status, icon+text never color-alone), a Marketplace Readiness
checklist, quick links. All derived from real facade/schema signals
(required-field fill state, modifiedSections, staticPages, catalog
counts via BackofficeDataService) or explicitly marked unknown
(the "preview reviewed" check has no tracking - shown as unknown,
never guessed).
Section pages (/edit/:section) now share one consistent header:
breadcrumb (Builder > Group > Section), draft/published + modified
badges, and a contextual help panel (what is this / where visible /
what happens if you skip it) sourced per group. Sidebar nav rewritten
as grouped, icon-led sections with per-section and per-group status
indicators; layout converted from a top pill-tab bar to a responsive
sidebar (desktop 280px, tablet 72px icon rail, mobile drawer with
Escape-to-close), matching the Sprint 1 admin shell pattern. Section
form components themselves untouched.
Routes: 'edit' is now its own landing route instead of redirecting to
'edit/general'; /builder and /project-editor redirect to 'edit'.
Sprint 1/2 destinations that pointed at edit/general now point at the
new edit landing page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 09:43:03 +04:00
|
|
|
appName: string;
|
2026-07-19 08:25:29 +04:00
|
|
|
backToDashboard: string;
|
2026-07-19 08:53:10 +04:00
|
|
|
languagesSummaryDesc: string;
|
|
|
|
|
manageLanguages: string;
|
2026-07-19 08:48:22 +04:00
|
|
|
htmlToolBold: string;
|
|
|
|
|
htmlToolItalic: string;
|
|
|
|
|
htmlToolUnderline: string;
|
|
|
|
|
htmlToolHeading: string;
|
|
|
|
|
htmlToolSubheading: string;
|
|
|
|
|
htmlToolBulletList: string;
|
|
|
|
|
htmlToolNumberedList: string;
|
|
|
|
|
htmlToolLink: string;
|
|
|
|
|
htmlToolImage: string;
|
|
|
|
|
htmlToolTable: string;
|
|
|
|
|
htmlToolDivider: string;
|
|
|
|
|
htmlToolCodeBlock: string;
|
|
|
|
|
htmlToolEmbed: string;
|
|
|
|
|
|
feat(builder): redesign marketplace builder experience and navigation
Renamed the experience consistently to Marketplace Builder everywhere
visible (page title/subtitle, breadcrumbs, sidebar, dashboard quick
action/shortcut copy) - internal ProjectEditor class/selector names
kept as-is to avoid regressions. builder.title/subtitle no longer say
'bootstrap-config editing surface' to end users.
New business-oriented IA (builder-groups.model.ts): 12 existing
ProjectEditorSectionIds regrouped into 8 groups (Marketplace, Branding
and Design, Homepage, Content, Languages, Marketplace Features,
Navigation and Search, Preview) - every existing section mapped to
exactly one group, none dropped, no group points at a page that
doesn't exist.
New Builder landing page at /edit (was a redirect straight into the
General form): readiness percent, recommended next step, one overview
card per group (purpose + real complete/in-progress/not-started/unknown
status, icon+text never color-alone), a Marketplace Readiness
checklist, quick links. All derived from real facade/schema signals
(required-field fill state, modifiedSections, staticPages, catalog
counts via BackofficeDataService) or explicitly marked unknown
(the "preview reviewed" check has no tracking - shown as unknown,
never guessed).
Section pages (/edit/:section) now share one consistent header:
breadcrumb (Builder > Group > Section), draft/published + modified
badges, and a contextual help panel (what is this / where visible /
what happens if you skip it) sourced per group. Sidebar nav rewritten
as grouped, icon-led sections with per-section and per-group status
indicators; layout converted from a top pill-tab bar to a responsive
sidebar (desktop 280px, tablet 72px icon rail, mobile drawer with
Escape-to-close), matching the Sprint 1 admin shell pattern. Section
form components themselves untouched.
Routes: 'edit' is now its own landing route instead of redirecting to
'edit/general'; /builder and /project-editor redirect to 'edit'.
Sprint 1/2 destinations that pointed at edit/general now point at the
new edit landing page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 09:43:03 +04:00
|
|
|
breadcrumbRoot: string;
|
|
|
|
|
statusComplete: string;
|
|
|
|
|
statusInProgress: string;
|
|
|
|
|
statusNotStarted: string;
|
|
|
|
|
statusUnknown: string;
|
|
|
|
|
draftBadge: string;
|
|
|
|
|
publishedBadge: string;
|
|
|
|
|
modifiedBadge: string;
|
|
|
|
|
helpToggleShow: string;
|
|
|
|
|
helpToggleHide: string;
|
|
|
|
|
helpWhatIsThis: string;
|
|
|
|
|
helpWhySkip: string;
|
|
|
|
|
helpWhereVisible: string;
|
|
|
|
|
helpWhatIfSkip: string;
|
|
|
|
|
helpWhenReturn: string;
|
|
|
|
|
openSidebar: string;
|
|
|
|
|
closeSidebar: string;
|
|
|
|
|
overviewTitle: string;
|
|
|
|
|
overviewSubtitle: string;
|
|
|
|
|
overviewReadinessLabel: string;
|
|
|
|
|
overviewReadinessHint: string;
|
|
|
|
|
overviewNextStepLabel: string;
|
|
|
|
|
overviewNextStepFallback: string;
|
|
|
|
|
overviewQuickLinksTitle: string;
|
|
|
|
|
overviewSectionsTitle: string;
|
|
|
|
|
overviewOpenSection: string;
|
|
|
|
|
overviewReadinessTitle: string;
|
|
|
|
|
readinessLogoUploaded: string;
|
|
|
|
|
readinessHomepageConfigured: string;
|
|
|
|
|
readinessThemeConfigured: string;
|
|
|
|
|
readinessLanguagesConfigured: string;
|
|
|
|
|
readinessContentPagesAdded: string;
|
|
|
|
|
readinessPreviewReviewed: string;
|
|
|
|
|
readinessPublished: string;
|
|
|
|
|
readinessCategoriesExist: string;
|
|
|
|
|
readinessProductsExist: string;
|
|
|
|
|
groupMarketplaceLabel: string;
|
|
|
|
|
groupMarketplaceDescription: string;
|
|
|
|
|
groupMarketplacePurpose: string;
|
|
|
|
|
groupMarketplaceWhere: string;
|
|
|
|
|
groupMarketplaceSkip: string;
|
|
|
|
|
groupBrandingLabel: string;
|
|
|
|
|
groupBrandingDescription: string;
|
|
|
|
|
groupBrandingPurpose: string;
|
|
|
|
|
groupBrandingWhere: string;
|
|
|
|
|
groupBrandingSkip: string;
|
|
|
|
|
groupHomepageLabel: string;
|
|
|
|
|
groupHomepageDescription: string;
|
|
|
|
|
groupHomepagePurpose: string;
|
|
|
|
|
groupHomepageWhere: string;
|
|
|
|
|
groupHomepageSkip: string;
|
|
|
|
|
groupContentLabel: string;
|
|
|
|
|
groupContentDescription: string;
|
|
|
|
|
groupContentPurpose: string;
|
|
|
|
|
groupContentWhere: string;
|
|
|
|
|
groupContentSkip: string;
|
|
|
|
|
groupLanguagesLabel: string;
|
|
|
|
|
groupLanguagesDescription: string;
|
|
|
|
|
groupLanguagesPurpose: string;
|
|
|
|
|
groupLanguagesWhere: string;
|
|
|
|
|
groupLanguagesSkip: string;
|
|
|
|
|
groupFeaturesLabel: string;
|
|
|
|
|
groupFeaturesDescription: string;
|
|
|
|
|
groupFeaturesPurpose: string;
|
|
|
|
|
groupFeaturesWhere: string;
|
|
|
|
|
groupFeaturesSkip: string;
|
|
|
|
|
groupNavigationLabel: string;
|
|
|
|
|
groupNavigationDescription: string;
|
|
|
|
|
groupNavigationPurpose: string;
|
|
|
|
|
groupNavigationWhere: string;
|
|
|
|
|
groupNavigationSkip: string;
|
|
|
|
|
groupPreviewLabel: string;
|
|
|
|
|
groupPreviewDescription: string;
|
|
|
|
|
groupPreviewPurpose: string;
|
|
|
|
|
groupPreviewWhere: string;
|
|
|
|
|
groupPreviewSkip: string;
|
feat(builder): implement professional brand management experience
New BrandOverviewComponent, mounted at the top of the existing
Branding section page (no route/schema/business-logic changes):
- Completion ring + recommended next step + last-modified timestamp,
computed from real facade signals (branding.logoUrl/faviconUrl/
socialImageUrl, theme.palette, theme.typography, lastSavedAt) -
nothing fabricated.
- Brand Health checklist (6 items: logo, favicon, colors, typography,
social image, accessibility) - icon+text, never color alone.
- Color palette preview: 10 swatches from the real ThemePaletteConfig
(primary/secondary/accent/success/warning/danger/backgrounds/text/
border), each with a readable label.
- Real WCAG contrast check (contrast.util.ts, relative-luminance
formula) between configured text and background colors - shows an
inline warning when below 4.5:1, never blocks publishing.
- Typography live preview using the configured heading/body font
families and base size.
- Social share preview card (Open Graph-style) using the existing
socialImageUrl + seo.default.title/description, with an explicit
empty state when no image is set yet.
Scope cut from the full brief given this session's cost already well
over budget entering this sprint - see Known limitations in the final
report (no multi-variant logo/favicon management, no live responsive
device preview, no new media library/asset picker; all reuse the
existing single-logo/single-favicon fields and image-field upload
component as-is).
Could not verify live in-browser this sprint: port 4200 is held by
another chat's dev server. Verified via `tsc --noEmit` (clean) and
manual template/binding review only; one binding (`--pct` custom-
property style binding) was replaced with a plain computed string to
remove an unverifiable risk rather than ship it unverified.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 10:13:35 +04:00
|
|
|
brandOverviewTitle: string;
|
|
|
|
|
brandOverviewSubtitle: string;
|
|
|
|
|
brandOverviewComplete: string;
|
|
|
|
|
brandLastModified: string;
|
|
|
|
|
brandFaviconUploaded: string;
|
|
|
|
|
brandColorsSelected: string;
|
|
|
|
|
brandTypographyConfigured: string;
|
|
|
|
|
brandSocialImageUploaded: string;
|
|
|
|
|
brandAccessibilityPassed: string;
|
|
|
|
|
brandColorsPreviewTitle: string;
|
|
|
|
|
brandTypographyPreviewTitle: string;
|
|
|
|
|
brandSocialPreviewTitle: string;
|
|
|
|
|
brandTypeSampleHeading: string;
|
|
|
|
|
brandTypeSampleBody: string;
|
|
|
|
|
brandContrastWarning: string;
|
|
|
|
|
brandSocialEmpty: string;
|
|
|
|
|
brandAccentColor: string;
|
|
|
|
|
brandBorderColor: string;
|
feat(builder): implement visual homepage builder
New HomepageOverviewComponent (Tasks 1+8), mounted at the top of the
existing Homepage section page: completion ring, active/hidden section
counts, recommended next step, last-modified timestamp, and a 6-item
Homepage Health checklist (hero/categories/products/promotion/
newsletter/any-sections) - all derived from the real page.sections/
widgets data already in the facade, nothing fabricated.
Existing page-level drag-and-drop reordering (homepage-section's
CdkDragDrop over page.sections) was already implemented pre-Sprint 5 -
left as-is per "build on top of, do not replace."
Widgets section (Task 2) rewritten from a bare list into visual cards:
per-widget icon + humanized type label (hero/categories/product-
collection), a visible/hidden toggle and badge, up/down move buttons
(keyboard-accessible reorder within a section - see Known limitations
for why this replaces pointer drag for widgets specifically), duplicate,
and remove (with confirm). The existing per-type field editors (hero/
categories/product-collection) are unchanged; the raw-JSON fallback for
unknown widget types now sits behind a collapsed "Advanced settings"
disclosure instead of being the default view.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 10:24:13 +04:00
|
|
|
homepageOverviewTitle: string;
|
|
|
|
|
homepageOverviewSubtitle: string;
|
|
|
|
|
homepageOverviewComplete: string;
|
|
|
|
|
homepageActiveSections: string;
|
|
|
|
|
homepageDisabledSections: string;
|
|
|
|
|
homepageHealthHero: string;
|
|
|
|
|
homepageHealthCategories: string;
|
|
|
|
|
homepageHealthProducts: string;
|
|
|
|
|
homepageHealthPromotion: string;
|
|
|
|
|
homepageHealthNewsletter: string;
|
|
|
|
|
homepageHealthAnySections: string;
|
|
|
|
|
widgetTypeHero: string;
|
|
|
|
|
widgetTypeCategories: string;
|
|
|
|
|
widgetTypeProducts: string;
|
|
|
|
|
widgetHidden: string;
|
|
|
|
|
widgetVisible: string;
|
|
|
|
|
widgetMoveUp: string;
|
|
|
|
|
widgetMoveDown: string;
|
|
|
|
|
widgetDuplicate: string;
|
|
|
|
|
widgetRemove: string;
|
|
|
|
|
widgetRemoveConfirm: string;
|
|
|
|
|
widgetAdvancedSettings: string;
|
fix(builder): composition audit fixes for project editor sections
- Reset-section button: raw <button> with hardcoded colors -> app-button variant="danger"
- section.shared.scss: raw button/input/select colors switched to CSS theme vars (--primary-color, --bg-primary, --bg-secondary, --error-color) instead of bare hex
- save-bar scss referenced nonexistent CSS vars (--surface, --border, --warning, --danger, --muted-foreground, --info-bg, --info) that always fell back to hardcoded hex; renamed to the real theme vars (--bg-primary, --border-color, --warning-color, --error-color, --text-secondary, --info-color) so the save bar is actually theme-aware
- footer/homepage/widgets section scss: nonexistent --danger-color var renamed to --error-color
- static-pages-editor: replaced dead `.editor-section-card` wrapper class (removed from shared stylesheet in the Sprint 30 redesign, never migrated here) with app-section-card, restoring the card chrome every sibling editor section has
- widgets-section: empty state (no widgets) rendered nothing; added app-empty-state
- homepage-section: empty state (no homepage page) rendered nothing; added app-empty-state
- navigation-section: header/footer nav move-up/move-down buttons had no accessible name (bare uarr/darr glyphs); added aria-label
- Added builder.widgetsEmptyTitle/Desc and builder.homepageEmptyTitle/Desc i18n keys (en/ru/hy)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 10:47:37 +04:00
|
|
|
widgetsEmptyTitle: string;
|
|
|
|
|
widgetsEmptyDesc: string;
|
|
|
|
|
homepageEmptyTitle: string;
|
|
|
|
|
homepageEmptyDesc: string;
|
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel.
Homepage section (sections list -> visual blocks):
- Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html
- Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3')
- Added duplicate and remove per block, alongside the existing drag-to-reorder
- Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end
Widgets section (hero widget):
- 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind
- 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values
- New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before
- HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control
Carousel arrows root cause and fix:
- widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place
- Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise
- Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug
New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
|
|
|
homepageBlocksHint: string;
|
|
|
|
|
addBlockHint: string;
|
|
|
|
|
dragToReorder: string;
|
2026-07-27 10:00:42 +04:00
|
|
|
livePreviewTitle: string;
|
|
|
|
|
livePreviewHint: string;
|
|
|
|
|
livePreviewEmpty: string;
|
|
|
|
|
livePreviewButtonLabel: string;
|
|
|
|
|
usedByLabel: string;
|
|
|
|
|
usedByHeader: string;
|
|
|
|
|
usedByFooter: string;
|
|
|
|
|
usedBySeo: string;
|
|
|
|
|
usedByButtons: string;
|
|
|
|
|
usedByLinks: string;
|
|
|
|
|
usedByBadges: string;
|
|
|
|
|
usedByPageBackground: string;
|
feat: Page Editor UX Phase 2 - unsaved changes panel, property search, reset property, empty states
- ProjectEditorFacade.resetField(key): field-level revert-to-original, reusing getByPath + a new immutable setByPath (write-side counterpart, scalar/object dot-paths only).
- app-form-field gains showReset/resetLabel/(resetClicked) - a reusable per-field reset affordance, wired on branding logo/title and theme primary/background color.
- Save bar: unsaved-changes count is now clickable, expanding a field-level diff list (reuses facade.changeSummary(), already built for the Preview tab) with jump-to-section links.
- BuilderPropertySearchComponent: filters EditorSchemaService.all() by translated label/hint, jumps to the owning section - no new registry, reuses the existing schema.
- navigation-section: app-empty-state (existing component) added for empty header/footer link lists.
- Reset Section and Draft/Published badge were already implemented; not touched.
- New copy added as translation keys (en/ru/hy).
2026-07-27 11:12:35 +04:00
|
|
|
resetField: string;
|
|
|
|
|
propertySearchLabel: string;
|
|
|
|
|
propertySearchPlaceholder: string;
|
|
|
|
|
propertySearchResultsLabel: string;
|
|
|
|
|
propertySearchNoResults: string;
|
|
|
|
|
unsavedChangesPanelTitle: string;
|
|
|
|
|
navigationHeaderEmptyTitle: string;
|
|
|
|
|
navigationHeaderEmptyDesc: string;
|
|
|
|
|
navigationFooterEmptyTitle: string;
|
|
|
|
|
navigationFooterEmptyDesc: string;
|
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel.
Homepage section (sections list -> visual blocks):
- Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html
- Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3')
- Added duplicate and remove per block, alongside the existing drag-to-reorder
- Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end
Widgets section (hero widget):
- 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind
- 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values
- New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before
- HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control
Carousel arrows root cause and fix:
- widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place
- Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise
- Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug
New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
|
|
|
blockRemoveConfirm: string;
|
|
|
|
|
blockHero: string;
|
|
|
|
|
blockHeroDesc: string;
|
|
|
|
|
blockCategories: string;
|
|
|
|
|
blockCategoriesDesc: string;
|
|
|
|
|
blockFeaturedProducts: string;
|
|
|
|
|
blockFeaturedProductsDesc: string;
|
|
|
|
|
blockProductCarousel: string;
|
|
|
|
|
blockProductCarouselDesc: string;
|
|
|
|
|
blockRecentlyViewed: string;
|
|
|
|
|
blockRecentlyViewedDesc: string;
|
|
|
|
|
blockBanner: string;
|
|
|
|
|
blockBannerDesc: string;
|
|
|
|
|
blockPartners: string;
|
|
|
|
|
blockPartnersDesc: string;
|
|
|
|
|
blockCustomHtml: string;
|
|
|
|
|
blockCustomHtmlDesc: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
};
|
2026-07-14 12:21:33 +04:00
|
|
|
dashboard: {
|
|
|
|
|
title: string;
|
|
|
|
|
subtitle: string;
|
|
|
|
|
cardMarketplaceStatus: string;
|
|
|
|
|
cardProjectName: string;
|
|
|
|
|
cardCurrentTheme: string;
|
|
|
|
|
cardLanguages: string;
|
|
|
|
|
cardCategoriesCount: string;
|
|
|
|
|
cardProductsCount: string;
|
|
|
|
|
cardOrders: string;
|
|
|
|
|
cardRevenue: string;
|
|
|
|
|
cardLastPublish: string;
|
|
|
|
|
cardLastDraftSave: string;
|
|
|
|
|
cardBootstrapVersion: string;
|
|
|
|
|
cardActiveLayout: string;
|
|
|
|
|
cardEnabledWidgets: string;
|
|
|
|
|
stateLoading: string;
|
|
|
|
|
stateEmpty: string;
|
|
|
|
|
stateError: string;
|
|
|
|
|
statePendingBackend: string;
|
|
|
|
|
never: string;
|
|
|
|
|
quickActionsTitle: string;
|
|
|
|
|
actionEditProject: string;
|
|
|
|
|
actionCategories: string;
|
|
|
|
|
actionProducts: string;
|
|
|
|
|
actionStaticPages: string;
|
|
|
|
|
actionTransactions: string;
|
|
|
|
|
actionOrders: string;
|
|
|
|
|
actionMediaLibrary: string;
|
2026-07-15 20:25:12 +04:00
|
|
|
actionUsers: string;
|
|
|
|
|
actionMonitoring: string;
|
|
|
|
|
actionAnalytics: string;
|
2026-07-14 12:21:33 +04:00
|
|
|
actionPreviewMarketplace: string;
|
|
|
|
|
activityTitle: string;
|
|
|
|
|
activityEmpty: string;
|
|
|
|
|
activityDraftSaved: string;
|
|
|
|
|
activityPublished: string;
|
|
|
|
|
healthTitle: string;
|
|
|
|
|
healthAllClear: string;
|
|
|
|
|
healthBootstrapValid: string;
|
|
|
|
|
healthConfigurationValid: string;
|
|
|
|
|
healthMissingTranslations: string;
|
|
|
|
|
healthInvalidColors: string;
|
|
|
|
|
healthInvalidWidgetReferences: string;
|
|
|
|
|
healthInvalidLayouts: string;
|
|
|
|
|
comingSoonTitle: string;
|
|
|
|
|
comingSoonDescription: string;
|
|
|
|
|
backToDashboard: string;
|
feat(admin): redesign dashboard into professional SaaS homepage
Replaced the placeholder dashboard with a real business homepage built
on 6 new reusable widget components (DashboardSection, DashboardCard,
DashboardMetric, DashboardStatusRow, DashboardTimeline,
DashboardShortcutCard), all wired through shared app-card/app-skeleton/
app-empty-state.
Sections: Welcome (tenant, env badge, current user, last publish/save -
all real facade signals, never blank), Quick Actions (large cards: add
product, create category, open builder, edit homepage, media, orders),
Draft Status (real dirty/modifiedFields/publish/discard from
ProjectEditorFacade), Marketplace Health (9 checks - config, product/
category counts, missing translations, draft, static-pages-unpublished,
homepage/theme configured, all real; images-without-alt shown as
'not tracked yet' rather than fabricated), Recent Activity (existing
localStorage-backed history service, loading/empty states), Useful
Shortcuts, Documentation (honest coming-soon list, no dead links).
12-column responsive grid: 3-across cards on desktop, 2-column on
tablet, single column on mobile, no horizontal scroll. Keyboard/focus/
ARIA per shortcut card and status row; health status never conveyed by
color alone (icon + text every time).
AdminDashboardHealthCheck (boolean 'healthy' shape) and its facade
signal are untouched - AdminMonitoringPageComponent also consumes them.
New richer status data lives in a separate homeHealthChecks signal/
AdminDashboardHomeHealthCheck type instead of widening the shared one.
Added ~50 new dashboard.* / kept existing i18n strings across ru/en/hy;
no raw keys.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 08:59:29 +04:00
|
|
|
welcomeEyebrow: string;
|
|
|
|
|
welcomeFallbackTenant: string;
|
|
|
|
|
envProduction: string;
|
|
|
|
|
envDevelopment: string;
|
|
|
|
|
factCurrentUser: string;
|
|
|
|
|
factTenant: string;
|
|
|
|
|
quickActionsDescription: string;
|
|
|
|
|
actionAddProduct: string;
|
|
|
|
|
actionAddProductDescription: string;
|
|
|
|
|
actionCreateCategory: string;
|
|
|
|
|
actionCreateCategoryDescription: string;
|
|
|
|
|
actionEditProjectDescription: string;
|
|
|
|
|
actionEditHomepage: string;
|
|
|
|
|
actionEditHomepageDescription: string;
|
|
|
|
|
actionMediaLibraryDescription: string;
|
|
|
|
|
actionOrdersDescription: string;
|
|
|
|
|
draftStatusTitle: string;
|
|
|
|
|
draftStatusHasChanges: string;
|
|
|
|
|
draftStatusAllPublished: string;
|
|
|
|
|
draftStatusMoreFields: string;
|
|
|
|
|
draftOpenBuilder: string;
|
|
|
|
|
draftPublish: string;
|
|
|
|
|
draftDiscard: string;
|
|
|
|
|
healthProductsCount: string;
|
|
|
|
|
healthCategoriesCount: string;
|
|
|
|
|
healthDraftExists: string;
|
|
|
|
|
healthImagesWithoutAlt: string;
|
|
|
|
|
healthStaticPagesUnpublished: string;
|
|
|
|
|
healthHomepageConfigured: string;
|
|
|
|
|
healthThemeConfigured: string;
|
|
|
|
|
statusHealthy: string;
|
|
|
|
|
statusAttention: string;
|
|
|
|
|
statusUnhealthy: string;
|
|
|
|
|
statusUnknown: string;
|
|
|
|
|
activityEmptyHint: string;
|
|
|
|
|
activityUnavailable: string;
|
|
|
|
|
activityUnavailableHint: string;
|
|
|
|
|
activityErrorHint: string;
|
|
|
|
|
shortcutsTitle: string;
|
|
|
|
|
shortcutsDescription: string;
|
|
|
|
|
shortcutMarketplaceBuilder: string;
|
|
|
|
|
shortcutSettings: string;
|
|
|
|
|
shortcutContent: string;
|
|
|
|
|
docTitle: string;
|
|
|
|
|
docDocumentation: string;
|
|
|
|
|
docKeyboardShortcuts: string;
|
|
|
|
|
docReportIssue: string;
|
|
|
|
|
docReleaseNotes: string;
|
2026-07-14 12:21:33 +04:00
|
|
|
};
|
2026-07-10 13:52:01 +04:00
|
|
|
staticPages: {
|
|
|
|
|
notFound: string;
|
|
|
|
|
backHome: string;
|
|
|
|
|
duplicateSlug: string;
|
|
|
|
|
emptyTitle: string;
|
feat(static-pages): CRUD completion + search/filter/bulk actions
Milestone 2 of the Static Pages Module sprint.
- StaticPagesEditorComponent: duplicate page, confirm-before-delete/bulk-
delete (matches the resetDraft confirm pattern), route/enabled/customTemplate/
media(hero/thumbnail/gallery) fields wired into the card, per-page publish/
unpublish action, status + duplicate-route/invalid-html/invalid-seo badges.
- Search (id/slug/route/title across all locales), filter by status
(draft/published) and by locale (hides pages missing a translation for the
selected locale) - all local computed() filters, no new service.
- Bulk selection (per-row + select-all-visible checkboxes) with bulk delete/
enable/disable/publish/unpublish, one updateBootstrap() call each.
- Correctness note: introduced `allPages` (unfiltered) vs `pages` (filtered
view) computeds. Every mutation (create/duplicate/delete/move/bulk) reads
from allPages(), never the filtered pages() - reading from the filtered
view would have silently deleted whatever an active search/filter hid on
the next persist(). Documented inline on persist() as a guardrail for
future edits.
- Fixed a template compile error found by the build gate: Angular templates
don't support inline arrow functions in binding expressions
((ngModelChange)="...map(v => v.trim())..." failed to parse) - moved the
gallery CSV-parsing into a component method (updateGallery).
- SEO robots field added to the page card (validated against a known-token
set from M1).
- i18n: staticPages.* extended (search/filter/bulk/route/enabled/status/
media/robots/disabled labels) across the interface + en/ru/hy.
Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:55:21 +04:00
|
|
|
duplicateRoute: string;
|
|
|
|
|
invalidHtml: string;
|
|
|
|
|
invalidSeo: string;
|
|
|
|
|
searchPlaceholder: string;
|
|
|
|
|
filterAll: string;
|
|
|
|
|
filterAllLocales: string;
|
|
|
|
|
confirmDeletePage: string;
|
|
|
|
|
confirmBulkDelete: string;
|
|
|
|
|
duplicatePage: string;
|
|
|
|
|
selectAll: string;
|
|
|
|
|
selectedCount: string;
|
|
|
|
|
bulkDelete: string;
|
|
|
|
|
bulkEnable: string;
|
|
|
|
|
bulkDisable: string;
|
|
|
|
|
bulkPublishAction: string;
|
|
|
|
|
bulkUnpublish: string;
|
|
|
|
|
routeLabel: string;
|
|
|
|
|
enabledLabel: string;
|
|
|
|
|
statusLabel: string;
|
|
|
|
|
publishPageAction: string;
|
|
|
|
|
unpublishPageAction: string;
|
|
|
|
|
heroImageLabel: string;
|
|
|
|
|
thumbnailLabel: string;
|
|
|
|
|
galleryLabel: string;
|
|
|
|
|
customTemplateLabel: string;
|
|
|
|
|
seoRobotsLabel: string;
|
|
|
|
|
disabledBadge: string;
|
2026-07-17 10:11:31 +04:00
|
|
|
previewDesktop: string;
|
|
|
|
|
previewTablet: string;
|
|
|
|
|
previewMobile: string;
|
|
|
|
|
previewToggle: string;
|
2026-07-10 13:52:01 +04:00
|
|
|
};
|
2026-07-18 11:02:26 +04:00
|
|
|
contentManagement: {
|
|
|
|
|
publishedPages: string;
|
|
|
|
|
draftPages: string;
|
|
|
|
|
missingLegalPages: string;
|
|
|
|
|
seoHealth: string;
|
|
|
|
|
lastEdited: string;
|
|
|
|
|
lastEditedNever: string;
|
|
|
|
|
completionLabel: string;
|
|
|
|
|
recommendedNext: string;
|
|
|
|
|
recommendAddTitles: string;
|
|
|
|
|
recommendFixSeo: string;
|
|
|
|
|
recommendPublish: string;
|
|
|
|
|
recommendNone: string;
|
|
|
|
|
openAction: string;
|
|
|
|
|
backToPages: string;
|
|
|
|
|
groupContent: string;
|
|
|
|
|
groupSeo: string;
|
|
|
|
|
groupSharing: string;
|
|
|
|
|
groupAdvanced: string;
|
|
|
|
|
groupAdvancedHtml: string;
|
2026-07-25 20:43:43 +04:00
|
|
|
pageContentLabel: string;
|
|
|
|
|
pageContentDesc: string;
|
2026-07-18 11:02:26 +04:00
|
|
|
seoExplainDesc: string;
|
|
|
|
|
seoTitleHelp: string;
|
|
|
|
|
seoDescriptionHelp: string;
|
|
|
|
|
seoCanonicalHelp: string;
|
|
|
|
|
seoRobotsHelp: string;
|
|
|
|
|
sharingExplain: string;
|
|
|
|
|
mediaSelect: string;
|
|
|
|
|
mediaReplace: string;
|
|
|
|
|
mediaRemove: string;
|
|
|
|
|
mediaAlt: string;
|
|
|
|
|
mediaCaption: string;
|
|
|
|
|
emptyStateGuideTitle: string;
|
|
|
|
|
emptyStateGuideBody: string;
|
|
|
|
|
seoStatusGood: string;
|
|
|
|
|
seoStatusPartial: string;
|
|
|
|
|
seoStatusWarning: string;
|
|
|
|
|
seoStatusMissing: string;
|
|
|
|
|
needsAttention: string;
|
|
|
|
|
legal: {
|
|
|
|
|
about: { label: string; why: string };
|
|
|
|
|
contacts: { label: string; why: string };
|
|
|
|
|
privacy: { label: string; why: string };
|
|
|
|
|
terms: { label: string; why: string };
|
|
|
|
|
cookies: { label: string; why: string };
|
|
|
|
|
delivery: { label: string; why: string };
|
|
|
|
|
returns: { label: string; why: string };
|
|
|
|
|
faq: { label: string; why: string };
|
|
|
|
|
};
|
|
|
|
|
};
|
2026-07-09 02:29:12 +04:00
|
|
|
widgets: {
|
|
|
|
|
unavailable: string;
|
|
|
|
|
};
|
2026-02-26 23:09:20 +04:00
|
|
|
carousel: {
|
|
|
|
|
loading: string;
|
|
|
|
|
addToCart: string;
|
|
|
|
|
};
|
|
|
|
|
common: {
|
|
|
|
|
retry: string;
|
|
|
|
|
loading: string;
|
2026-07-17 15:22:45 +04:00
|
|
|
remove: string;
|
fix(backoffice): add error+retry states to Users, Monitoring, Analytics, Reports
Phase 8 (RC-01): these 4 list/dashboard pages had no error-state handling
on their primary data-load subscriptions — on a gateway error, `loading`
was either never reset (Users, Monitoring, Analytics: genuine infinite-
spinner risk, nested subscribe chain in Analytics never resolved on
failure) or there was no loading/empty/error handling at all (Reports
queue: raw table with zero skeleton or fallback).
- admin-users.facade.ts, admin-monitoring.facade.ts: add `error` signal,
error callback on the primary load subscribe so `loading` always
resolves.
- admin-analytics.facade.ts: add `error` signal; every level of the
4-deep nested gateway subscribe chain (orders -> products ->
categories -> reviews) now has an error handler that resolves loading
instead of leaving it stuck true.
- admin-moderation.facade.ts: add `reportsLoading`/`reportsError` signals
(reports list had none previously).
- Templates: reuse existing `app-skeleton`/`app-empty-state`/`app-button`
primitives for the new error branch, `common.retry` label, two new
generic `common.errorTitle`/`common.errorDescription` i18n keys added
to en/ru/hy (reused across all 4 fixes instead of one-off per-page
copy).
Verified: tsc --noEmit clean, `npm run build` green (pre-existing bundle-
budget warning only, unrelated). Live-checked Home (375px) and Backoffice
Products (1024px) — no console errors, tables/cards render without
overflow.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:31:30 +04:00
|
|
|
errorTitle: string;
|
|
|
|
|
errorDescription: string;
|
2026-07-25 23:54:08 +04:00
|
|
|
ratingLabel: string;
|
|
|
|
|
discountLabel: string;
|
|
|
|
|
slideLabel: string;
|
|
|
|
|
slidesLabel: string;
|
|
|
|
|
previousProducts: string;
|
|
|
|
|
nextProducts: string;
|
|
|
|
|
closeDialog: string;
|
|
|
|
|
dismiss: string;
|
|
|
|
|
qrCode: string;
|
|
|
|
|
bankCardPayment: string;
|
|
|
|
|
guest: string;
|
2026-07-26 00:08:00 +04:00
|
|
|
cancel: string;
|
|
|
|
|
confirm: string;
|
2026-02-26 23:09:20 +04:00
|
|
|
};
|
2026-02-28 17:18:24 +04:00
|
|
|
location: {
|
|
|
|
|
allRegions: string;
|
|
|
|
|
chooseRegion: string;
|
|
|
|
|
detectAuto: string;
|
|
|
|
|
};
|
|
|
|
|
auth: {
|
|
|
|
|
loginRequired: string;
|
|
|
|
|
loginDescription: string;
|
|
|
|
|
checking: string;
|
|
|
|
|
loginWithTelegram: string;
|
|
|
|
|
orScanQr: string;
|
|
|
|
|
loginNote: string;
|
2026-03-25 15:32:50 +04:00
|
|
|
qrExpired: string;
|
2026-06-01 00:47:26 +04:00
|
|
|
qrError: string;
|
2026-02-28 17:18:24 +04:00
|
|
|
};
|
2026-07-09 01:13:54 +04:00
|
|
|
ux: {
|
|
|
|
|
items: string;
|
|
|
|
|
wishlistTitle: string;
|
|
|
|
|
wishlistEmptyTitle: string;
|
|
|
|
|
wishlistEmptyDescription: string;
|
|
|
|
|
clearWishlist: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
wishlistCleared: string;
|
2026-07-09 01:13:54 +04:00
|
|
|
compareTitle: string;
|
|
|
|
|
compareEmptyTitle: string;
|
|
|
|
|
compareEmptyDescription: string;
|
|
|
|
|
clearCompare: string;
|
2026-07-19 23:35:17 +04:00
|
|
|
removeFromCompare: string;
|
2026-07-09 01:13:54 +04:00
|
|
|
hideIdentical: string;
|
|
|
|
|
highlightDifferences: string;
|
|
|
|
|
clearRecentlyViewed: string;
|
|
|
|
|
recentlyViewedEmpty: string;
|
|
|
|
|
saveSearch: string;
|
|
|
|
|
goToCatalog: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
wishlistAdded: string;
|
|
|
|
|
wishlistRemoved: string;
|
|
|
|
|
compareAdded: string;
|
|
|
|
|
compareRemoved: string;
|
|
|
|
|
compareLimitReached: string;
|
|
|
|
|
productShared: string;
|
|
|
|
|
productLinkCopied: string;
|
|
|
|
|
sharingUnsupported: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
addedToCart: string;
|
2026-07-09 01:40:22 +04:00
|
|
|
enterQueryBeforeSave: string;
|
|
|
|
|
savedSearchNamed: string;
|
2026-07-09 02:29:12 +04:00
|
|
|
recentlyViewedTitle: string;
|
|
|
|
|
compareAttribute: string;
|
|
|
|
|
comparePrice: string;
|
|
|
|
|
compareRating: string;
|
|
|
|
|
compareStock: string;
|
|
|
|
|
compareDiscount: string;
|
|
|
|
|
compareColor: string;
|
|
|
|
|
compareSize: string;
|
|
|
|
|
compareUnknown: string;
|
2026-07-09 01:13:54 +04:00
|
|
|
};
|
2026-07-10 13:34:25 +04:00
|
|
|
diagnostics: {
|
|
|
|
|
title: string;
|
|
|
|
|
disabledTitle: string;
|
|
|
|
|
disabledDescription: string;
|
|
|
|
|
generatedAt: string;
|
|
|
|
|
healthScore: string;
|
|
|
|
|
summary: string;
|
|
|
|
|
passedChecks: string;
|
|
|
|
|
warnings: string;
|
|
|
|
|
errors: string;
|
|
|
|
|
critical: string;
|
|
|
|
|
healthChecks: string;
|
|
|
|
|
results: string;
|
|
|
|
|
noIssues: string;
|
|
|
|
|
ok: string;
|
|
|
|
|
failed: string;
|
|
|
|
|
affectedComponent: string;
|
|
|
|
|
suggestedResolution: string;
|
|
|
|
|
severity: {
|
|
|
|
|
info: string;
|
|
|
|
|
warning: string;
|
|
|
|
|
error: string;
|
|
|
|
|
critical: string;
|
|
|
|
|
};
|
|
|
|
|
checks: {
|
|
|
|
|
bootstrapLoaded: string;
|
|
|
|
|
tenantResolved: string;
|
|
|
|
|
runtimeInitialized: string;
|
|
|
|
|
themeLoaded: string;
|
|
|
|
|
widgetManifestLoaded: string;
|
|
|
|
|
sectionEngineInitialized: string;
|
|
|
|
|
configurationEngineInitialized: string;
|
|
|
|
|
translationResourcesAvailable: string;
|
|
|
|
|
requiredAssetsAvailable: string;
|
|
|
|
|
};
|
|
|
|
|
bootstrapMissingTitle: string;
|
|
|
|
|
bootstrapMissingDescription: string;
|
|
|
|
|
bootstrapMissingResolution: string;
|
|
|
|
|
requiredPropertyMissingTitle: string;
|
|
|
|
|
requiredPropertyMissingDescription: string;
|
|
|
|
|
requiredPropertyMissingResolution: string;
|
|
|
|
|
unknownWidgetTypeTitle: string;
|
|
|
|
|
unknownWidgetTypeDescription: string;
|
|
|
|
|
unknownWidgetTypeResolution: string;
|
|
|
|
|
duplicateIdTitle: string;
|
|
|
|
|
duplicatePageIdDescription: string;
|
|
|
|
|
duplicateSectionIdDescription: string;
|
|
|
|
|
duplicateWidgetIdDescription: string;
|
|
|
|
|
duplicateIdResolution: string;
|
|
|
|
|
unknownLayoutTitle: string;
|
|
|
|
|
unknownLayoutDescription: string;
|
|
|
|
|
unknownLayoutResolution: string;
|
|
|
|
|
invalidFeatureFlagTitle: string;
|
|
|
|
|
invalidFeatureFlagDescription: string;
|
|
|
|
|
invalidFeatureFlagResolution: string;
|
|
|
|
|
brokenPageDefinitionTitle: string;
|
|
|
|
|
brokenPageDefinitionDescription: string;
|
|
|
|
|
brokenPageDefinitionResolution: string;
|
|
|
|
|
invalidNavigationTargetTitle: string;
|
|
|
|
|
invalidNavigationTargetDescription: string;
|
|
|
|
|
invalidNavigationTargetResolution: string;
|
|
|
|
|
missingTranslationTitle: string;
|
|
|
|
|
missingTranslationDescription: string;
|
|
|
|
|
missingTranslationResolution: string;
|
|
|
|
|
missingMediaTitle: string;
|
|
|
|
|
missingMediaDescription: string;
|
|
|
|
|
missingMediaResolution: string;
|
|
|
|
|
runtimeNotInitializedTitle: string;
|
|
|
|
|
runtimeNotInitializedDescription: string;
|
|
|
|
|
runtimeNotInitializedResolution: string;
|
|
|
|
|
configFallbackUsageTitle: string;
|
|
|
|
|
configFallbackUsageDescription: string;
|
|
|
|
|
configFallbackUsageResolution: string;
|
|
|
|
|
missingDatasourceTitle: string;
|
|
|
|
|
missingDatasourceDescription: string;
|
|
|
|
|
missingDatasourceResolution: string;
|
|
|
|
|
widgetRenderFailureTitle: string;
|
|
|
|
|
widgetRenderFailureDescription: string;
|
|
|
|
|
widgetRenderFailureResolution: string;
|
|
|
|
|
brokenRouteTitle: string;
|
|
|
|
|
brokenRouteDescription: string;
|
|
|
|
|
brokenRouteResolution: string;
|
|
|
|
|
imageLoadFailedTitle: string;
|
|
|
|
|
imageLoadFailedDescription: string;
|
|
|
|
|
imageLoadFailedResolution: string;
|
|
|
|
|
optionalDataMissingTitle: string;
|
|
|
|
|
optionalDataMissingDescription: string;
|
|
|
|
|
optionalDataMissingResolution: string;
|
|
|
|
|
};
|
feat(admin): implement review and moderation center
New Reviews & Moderation feature (frontend only): moderation dashboard (real pending/approved/rejected/reported/spam counts, average rating, recent activity, moderation-health%, computed from the full review queue); reviews list with table/cards, density, saved column visibility, search/status/rating filters, bulk approve/reject/spam/hide/export; review detail shows customer/product/rating/text/photos/timeline/moderator-notes with a real moderation workflow (approve/reject/spam/hide/restore/pin/feature, feature disabled with an explanation unless the review is approved); reusable ReviewHealthWidget (rating/text/media/moderated/report-status/visible + completion%); reports queue lists reports against products/reviews/customers/categories with resolve/dismiss, and honestly renders 'Not available yet' rather than fabricating a value wherever a target can't be resolved (e.g. photos, customer-target reports). Backed by a new in-memory AdminModerationLocalGateway seeded from real product data - the same mock-gateway pattern already used by every other admin feature in this app (orders/products/categories), since no review/report backend exists to reuse. Replaced the 'Reviews' comingSoon nav placeholder with a working link; added full adminModeration i18n coverage.
2026-07-18 22:01:16 +04:00
|
|
|
adminModeration: {
|
|
|
|
|
search: string;
|
2026-07-20 00:03:46 +04:00
|
|
|
selectAllRows: string;
|
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
|
|
|
itemsCount: string;
|
feat(admin): implement review and moderation center
New Reviews & Moderation feature (frontend only): moderation dashboard (real pending/approved/rejected/reported/spam counts, average rating, recent activity, moderation-health%, computed from the full review queue); reviews list with table/cards, density, saved column visibility, search/status/rating filters, bulk approve/reject/spam/hide/export; review detail shows customer/product/rating/text/photos/timeline/moderator-notes with a real moderation workflow (approve/reject/spam/hide/restore/pin/feature, feature disabled with an explanation unless the review is approved); reusable ReviewHealthWidget (rating/text/media/moderated/report-status/visible + completion%); reports queue lists reports against products/reviews/customers/categories with resolve/dismiss, and honestly renders 'Not available yet' rather than fabricating a value wherever a target can't be resolved (e.g. photos, customer-target reports). Backed by a new in-memory AdminModerationLocalGateway seeded from real product data - the same mock-gateway pattern already used by every other admin feature in this app (orders/products/categories), since no review/report backend exists to reuse. Replaced the 'Reviews' comingSoon nav placeholder with a working link; added full adminModeration i18n coverage.
2026-07-18 22:01:16 +04:00
|
|
|
allStatuses: string;
|
|
|
|
|
allRatings: string;
|
|
|
|
|
rating: string;
|
|
|
|
|
customer: string;
|
|
|
|
|
product: string;
|
|
|
|
|
reviewText: string;
|
|
|
|
|
photos: string;
|
|
|
|
|
workflow: string;
|
|
|
|
|
approve: string;
|
|
|
|
|
reject: string;
|
|
|
|
|
markSpam: string;
|
|
|
|
|
hide: string;
|
|
|
|
|
restore: string;
|
|
|
|
|
pin: string;
|
|
|
|
|
unpin: string;
|
|
|
|
|
feature: string;
|
|
|
|
|
unfeature: string;
|
|
|
|
|
featureDisabledHint: string;
|
|
|
|
|
moderatorNotes: string;
|
|
|
|
|
notAvailable: string;
|
|
|
|
|
changeStatus: string;
|
|
|
|
|
hideSelected: string;
|
|
|
|
|
archiveSelected: string;
|
|
|
|
|
reportsQueue: string;
|
|
|
|
|
reportsColumn: string;
|
|
|
|
|
reportTarget: string;
|
|
|
|
|
reportType: string;
|
|
|
|
|
reportReason: string;
|
|
|
|
|
resolve: string;
|
|
|
|
|
dismiss: string;
|
|
|
|
|
reportsEmptyTitle: string;
|
|
|
|
|
reportsEmptyDescription: string;
|
|
|
|
|
reportedCount: string;
|
|
|
|
|
averageRating: string;
|
|
|
|
|
moderationHealth: string;
|
|
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyDescription: string;
|
|
|
|
|
emptyGuide: string;
|
|
|
|
|
healthRating: string;
|
|
|
|
|
healthText: string;
|
|
|
|
|
healthMedia: string;
|
|
|
|
|
healthModeration: string;
|
|
|
|
|
healthReportStatus: string;
|
|
|
|
|
healthVisibility: string;
|
|
|
|
|
health: string;
|
|
|
|
|
column_product: string;
|
|
|
|
|
column_rating: string;
|
|
|
|
|
column_status: string;
|
|
|
|
|
column_reports: string;
|
|
|
|
|
column_created: string;
|
|
|
|
|
status: {
|
|
|
|
|
pending: string;
|
|
|
|
|
approved: string;
|
|
|
|
|
rejected: string;
|
|
|
|
|
spam: string;
|
|
|
|
|
};
|
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
|
|
|
timelineEvent: {
|
|
|
|
|
submitted: string;
|
|
|
|
|
statusChanged: string;
|
|
|
|
|
restored: string;
|
|
|
|
|
hidden: string;
|
|
|
|
|
};
|
|
|
|
|
actor: {
|
|
|
|
|
admin: string;
|
|
|
|
|
customer: string;
|
|
|
|
|
};
|
feat(admin): implement review and moderation center
New Reviews & Moderation feature (frontend only): moderation dashboard (real pending/approved/rejected/reported/spam counts, average rating, recent activity, moderation-health%, computed from the full review queue); reviews list with table/cards, density, saved column visibility, search/status/rating filters, bulk approve/reject/spam/hide/export; review detail shows customer/product/rating/text/photos/timeline/moderator-notes with a real moderation workflow (approve/reject/spam/hide/restore/pin/feature, feature disabled with an explanation unless the review is approved); reusable ReviewHealthWidget (rating/text/media/moderated/report-status/visible + completion%); reports queue lists reports against products/reviews/customers/categories with resolve/dismiss, and honestly renders 'Not available yet' rather than fabricating a value wherever a target can't be resolved (e.g. photos, customer-target reports). Backed by a new in-memory AdminModerationLocalGateway seeded from real product data - the same mock-gateway pattern already used by every other admin feature in this app (orders/products/categories), since no review/report backend exists to reuse. Replaced the 'Reviews' comingSoon nav placeholder with a working link; added full adminModeration i18n coverage.
2026-07-18 22:01:16 +04:00
|
|
|
targetType: {
|
|
|
|
|
product: string;
|
|
|
|
|
review: string;
|
|
|
|
|
customer: string;
|
|
|
|
|
category: string;
|
|
|
|
|
unknown: string;
|
|
|
|
|
};
|
|
|
|
|
reportStatus: {
|
|
|
|
|
open: string;
|
|
|
|
|
resolved: string;
|
|
|
|
|
dismissed: string;
|
|
|
|
|
};
|
|
|
|
|
};
|
2026-07-18 21:47:54 +04:00
|
|
|
adminOrders: {
|
|
|
|
|
back: string;
|
|
|
|
|
search: string;
|
|
|
|
|
export: string;
|
2026-07-20 00:00:29 +04:00
|
|
|
selectAllRows: string;
|
|
|
|
|
selectRow: string;
|
2026-07-18 21:47:54 +04:00
|
|
|
view: string;
|
|
|
|
|
orderNumber: string;
|
|
|
|
|
customer: string;
|
|
|
|
|
payment: string;
|
|
|
|
|
delivery: string;
|
|
|
|
|
trackingNumber: string;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
items: string;
|
|
|
|
|
timeline: string;
|
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
|
|
|
timelineEvent: {
|
|
|
|
|
created: string;
|
|
|
|
|
statusChanged: string;
|
|
|
|
|
refundRequested: string;
|
|
|
|
|
};
|
2026-07-18 21:47:54 +04:00
|
|
|
notes: string;
|
|
|
|
|
internalNotes: string;
|
|
|
|
|
addNote: string;
|
|
|
|
|
changeStatus: string;
|
|
|
|
|
applyStatus: string;
|
|
|
|
|
archiveSelected: string;
|
|
|
|
|
printSelected: string;
|
|
|
|
|
printInvoice: string;
|
|
|
|
|
requestRefund: string;
|
|
|
|
|
cancelOrder: string;
|
|
|
|
|
confirmCancel: string;
|
|
|
|
|
confirmRefund: string;
|
|
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyDescription: string;
|
|
|
|
|
column_customer: string;
|
|
|
|
|
column_status: string;
|
|
|
|
|
column_payment: string;
|
|
|
|
|
column_total: string;
|
|
|
|
|
column_created: string;
|
|
|
|
|
status: {
|
2026-07-19 23:04:51 +04:00
|
|
|
all: string;
|
2026-07-18 21:47:54 +04:00
|
|
|
pending: string;
|
|
|
|
|
processing: string;
|
|
|
|
|
shipped: string;
|
|
|
|
|
delivered: string;
|
|
|
|
|
cancelled: string;
|
|
|
|
|
refunded: string;
|
|
|
|
|
};
|
|
|
|
|
paymentStatus: {
|
|
|
|
|
unpaid: string;
|
|
|
|
|
paid: string;
|
|
|
|
|
refund_requested: string;
|
|
|
|
|
refunded: string;
|
|
|
|
|
};
|
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
|
|
|
itemsCount: string;
|
2026-07-18 21:47:54 +04:00
|
|
|
ordersToday: string;
|
|
|
|
|
paidCount: string;
|
|
|
|
|
customersCount: string;
|
|
|
|
|
returningCustomers: string;
|
|
|
|
|
averageOrder: string;
|
|
|
|
|
recentActivity: string;
|
|
|
|
|
noRecentActivity: string;
|
|
|
|
|
alertStuckPending: string;
|
|
|
|
|
alertRefundRequested: string;
|
|
|
|
|
};
|
|
|
|
|
adminCustomers: {
|
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
|
|
|
back: string;
|
2026-07-18 21:47:54 +04:00
|
|
|
search: string;
|
|
|
|
|
name: string;
|
|
|
|
|
email: string;
|
|
|
|
|
phone: string;
|
|
|
|
|
orderCount: string;
|
|
|
|
|
lifetimeValue: string;
|
|
|
|
|
returning: string;
|
|
|
|
|
profile: string;
|
|
|
|
|
statistics: string;
|
|
|
|
|
firstOrder: string;
|
|
|
|
|
lastOrder: string;
|
|
|
|
|
addresses: string;
|
|
|
|
|
notes: string;
|
|
|
|
|
notesUnavailable: string;
|
|
|
|
|
orders: string;
|
|
|
|
|
activity: string;
|
|
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyDescription: string;
|
|
|
|
|
};
|
feat(media): add Media Manager UI (grid, upload, delete)
MediaLibraryPageComponent replaces the coming-soon placeholder at
/backoffice/media. Built entirely on Sprint 6 Design System primitives
(app-card, app-button, app-input, app-empty-state, app-dialog, app-pagination,
app-skeleton) and Sprint 4 Task 2's MediaRepository/MockMediaRepository.
- Grid view with per-tile filename/size and delete action
- Hidden native file input triggered by an app-button, uploads via
MediaLibraryFacade -> MediaRepository.upload()
- Delete requires confirmation through app-dialog (destructive action)
- Search + pagination wired to MockMediaRepository's list() params
- Loading state shows app-skeleton tiles; empty state shows app-empty-state
- New mediaLibrary.* translation namespace across en/ru/hy
Verified in browser (via a temporary unguarded route, reverted before
commit - /backoffice/media itself requires Telegram QR admin auth not
available in this session): empty state renders correctly with translated
copy, search input and upload button present, no console errors.
2026-07-15 07:14:16 +04:00
|
|
|
mediaLibrary: {
|
|
|
|
|
title: string;
|
|
|
|
|
upload: string;
|
|
|
|
|
uploading: string;
|
|
|
|
|
searchPlaceholder: string;
|
|
|
|
|
delete: string;
|
|
|
|
|
deleteConfirmTitle: string;
|
|
|
|
|
deleteConfirmBody: string;
|
|
|
|
|
cancel: string;
|
|
|
|
|
confirm: string;
|
|
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyDescription: string;
|
feat(builder): implement reusable media library
Media dashboard (real total/images/SVG/logos/unused/storage/alt-coverage, computed from actual assets + a bootstrap usage scan, no fabricated stats); gallery gets grid/list toggle, type filter, sort, drag-and-drop + multi-file upload with cancel/retry and friendly error mapping, lazy thumbnails, multi-select with bulk delete/download/export-metadata; asset details drawer shows real dimensions/size/format/date/usage locations (walks bootstrap config for exact URL matches, reports not-used rather than guessing) plus editable alt text/caption/description/decorative flag with missing-alt warning; shared MediaPickerComponent (already the one reusable picker used by content management) gains type filter, a recent shortcut, and keyboard grid navigation.
2026-07-18 16:09:47 +04:00
|
|
|
allFolders: string;
|
|
|
|
|
newFolder: string;
|
|
|
|
|
editTags: string;
|
|
|
|
|
totalAssets: string;
|
|
|
|
|
logos: string;
|
|
|
|
|
unused: string;
|
|
|
|
|
storageUsed: string;
|
|
|
|
|
altCoverage: string;
|
|
|
|
|
allTypes: string;
|
|
|
|
|
typeImage: string;
|
|
|
|
|
typeSvg: string;
|
|
|
|
|
typePdf: string;
|
|
|
|
|
sortRecent: string;
|
|
|
|
|
sortName: string;
|
|
|
|
|
sortSize: string;
|
|
|
|
|
viewMode: string;
|
|
|
|
|
viewGrid: string;
|
|
|
|
|
viewList: string;
|
|
|
|
|
dropHint: string;
|
|
|
|
|
cancelUpload: string;
|
|
|
|
|
retry: string;
|
|
|
|
|
errorTooLarge: string;
|
|
|
|
|
errorUnsupportedType: string;
|
|
|
|
|
errorGeneric: string;
|
|
|
|
|
selectedCount: string;
|
|
|
|
|
download: string;
|
|
|
|
|
exportMetadata: string;
|
|
|
|
|
bulkDelete: string;
|
|
|
|
|
bulkDeleteConfirm: string;
|
|
|
|
|
clearSelection: string;
|
|
|
|
|
guideCopy: string;
|
|
|
|
|
missingAlt: string;
|
|
|
|
|
usageCount: string;
|
|
|
|
|
detailsTitle: string;
|
|
|
|
|
filename: string;
|
|
|
|
|
format: string;
|
|
|
|
|
fileSize: string;
|
|
|
|
|
dimensions: string;
|
|
|
|
|
uploadDate: string;
|
|
|
|
|
lastUsed: string;
|
|
|
|
|
usageCountLabel: string;
|
|
|
|
|
usedIn: string;
|
|
|
|
|
notUsed: string;
|
|
|
|
|
unknownValue: string;
|
|
|
|
|
altText: string;
|
|
|
|
|
altTextHelp: string;
|
|
|
|
|
decorative: string;
|
|
|
|
|
missingAltWarning: string;
|
|
|
|
|
caption: string;
|
|
|
|
|
description: string;
|
|
|
|
|
usage: {
|
|
|
|
|
brand: string;
|
|
|
|
|
theme: string;
|
|
|
|
|
header: string;
|
|
|
|
|
footer: string;
|
|
|
|
|
staticPage: string;
|
|
|
|
|
homepage: string;
|
|
|
|
|
catalog: string;
|
|
|
|
|
productPage: string;
|
|
|
|
|
widget: string;
|
|
|
|
|
company: string;
|
|
|
|
|
seo: string;
|
|
|
|
|
navigation: string;
|
|
|
|
|
other: string;
|
|
|
|
|
};
|
feat(media): add Media Manager UI (grid, upload, delete)
MediaLibraryPageComponent replaces the coming-soon placeholder at
/backoffice/media. Built entirely on Sprint 6 Design System primitives
(app-card, app-button, app-input, app-empty-state, app-dialog, app-pagination,
app-skeleton) and Sprint 4 Task 2's MediaRepository/MockMediaRepository.
- Grid view with per-tile filename/size and delete action
- Hidden native file input triggered by an app-button, uploads via
MediaLibraryFacade -> MediaRepository.upload()
- Delete requires confirmation through app-dialog (destructive action)
- Search + pagination wired to MockMediaRepository's list() params
- Loading state shows app-skeleton tiles; empty state shows app-empty-state
- New mediaLibrary.* translation namespace across en/ru/hy
Verified in browser (via a temporary unguarded route, reverted before
commit - /backoffice/media itself requires Telegram QR admin auth not
available in this session): empty state renders correctly with translated
copy, search input and upload button present, no console errors.
2026-07-15 07:14:16 +04:00
|
|
|
};
|
2026-07-16 00:19:41 +04:00
|
|
|
// Sprint 28: only the new empty-state copy this sprint's skeleton/empty-
|
|
|
|
|
// state consistency fix introduces - NOT the full adminProducts/
|
|
|
|
|
// adminUsers/adminMonitoring/adminAnalytics translation surface, which is
|
|
|
|
|
// still missing entirely (see docs/KNOWN-ISSUES.md, deferred to Sprint 29).
|
fix(static-pages): backfill enabled/status in export, fix missing i18n key
Independent review pass over the Static Pages Module sprint (M1-M7),
including live browser E2E per the task's own verification checklist.
- ProjectEditorFacade.normalize() now backfills enabled/status on
record-format static pages (defaulting missing values to enabled+published,
same rule ContentPageService.normalizePage applies for display - mirrored
rather than imported, to avoid a project-editor <-> content-management
circular dependency since ContentManagementFacade already depends on this
facade). Found live: exporting a page that predates this sprint and was
never touched/re-saved in the current session produced JSON missing
enabled/status entirely - the editor UI and storefront resolver both
normalize-on-read so nothing was actually broken live, but Export/Import
fidelity should match what the editor shows. Verified fixed live (export
now includes "enabled":true,"status":"published" for an untouched legacy
page) and via the full gate.
- Added the missing adminCategories.chooseImage i18n key (interface +
en/ru/hy). Found live: the media-picker "choose image" button rendered as
the literal string "adminCategories.chooseImage" - a pre-existing,
repo-wide bug (5 templates reference this key; none of the locale files
ever defined it) that I propagated into a 3rd/4th/5th... well, 2 new
occurrences by copying the existing branding-section/footer-section
pattern into static-pages-editor. Fixed the actual defect (missing
translation) rather than renaming the key, which would have required
touching 2 unrelated admin components outside this sprint's scope.
Live-verified this pass: Static Pages editor renders with all new fields;
create page works (page count 4->confirmed); device preview toggles
desktop/tablet/mobile widths correctly; navigation "Insert page link"
creates a real type:'staticPage' nav item end-to-end (confirmed in the
exported JSON); export includes all Sprint X+2 fields after the fix; no
console errors throughout.
Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:27:29 +04:00
|
|
|
// Shared across branding/footer/static-pages/admin-product/admin-category media
|
|
|
|
|
// pickers - despite the namespace name, this is a generic "choose image" label,
|
|
|
|
|
// not category-specific. Renaming is a separate cleanup outside this sprint's
|
|
|
|
|
// scope; the key was previously referenced by 5 templates but never defined
|
|
|
|
|
// anywhere, so it rendered as the literal string "adminCategories.chooseImage".
|
|
|
|
|
adminCategories: {
|
|
|
|
|
chooseImage: string;
|
2026-07-17 15:22:45 +04:00
|
|
|
replaceImage: string;
|
2026-07-18 17:04:11 +04:00
|
|
|
search: string;
|
|
|
|
|
showDeleted: string;
|
2026-07-19 23:57:49 +04:00
|
|
|
selectAllRows: string;
|
|
|
|
|
selectRow: string;
|
|
|
|
|
toggleVisibility: string;
|
2026-07-18 17:04:11 +04:00
|
|
|
create: string;
|
|
|
|
|
edit: string;
|
|
|
|
|
title: string;
|
|
|
|
|
slug: string;
|
|
|
|
|
slugTaken: string;
|
|
|
|
|
parent: string;
|
|
|
|
|
noParent: string;
|
|
|
|
|
icon: string;
|
|
|
|
|
image: string;
|
|
|
|
|
imageHint: string;
|
|
|
|
|
description: string;
|
|
|
|
|
items: string;
|
|
|
|
|
status: { draft: string; published: string };
|
|
|
|
|
restore: string;
|
|
|
|
|
saveDraft: string;
|
|
|
|
|
publish: string;
|
|
|
|
|
confirmDelete: string;
|
|
|
|
|
confirmLeaveUnsaved: string;
|
|
|
|
|
deleteBlocked: string;
|
|
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyDescription: string;
|
|
|
|
|
emptyGuide: string;
|
|
|
|
|
viewTree: string;
|
|
|
|
|
viewCards: string;
|
|
|
|
|
expandAll: string;
|
|
|
|
|
collapseAll: string;
|
|
|
|
|
expandNode: string;
|
|
|
|
|
collapseNode: string;
|
fix(backoffice): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, Backoffice (admin/*) area. Builds on 712a7b4/63c9cee's
composition pass (scope="col", skeletons, empty-states) without redoing that
work.
- Sidebar nav landmark: admin-layout's <nav aria-label> reused the
"Dashboard" nav-item translation key as its landmark label, misleadingly
announcing the whole sidebar as "Dashboard" - added a dedicated
adminShell.sidebarLabel key ("Admin sidebar navigation") in en/ru/hy.
Skip link, #admin-content main landmark, Escape handling, and mobile-drawer
focus management were already correct - verified, not touched.
- Categories tree drag-and-drop keyboard fallback (WCAG 2.1.1): the category
tree's native HTML5 DnD (draggable/dragstart/drop) reorders siblings with
no keyboard equivalent - existing arrow-key tree navigation only expands/
collapses/selects, never reorders. Added per-row move-up/move-down icon
buttons (disabled at sibling boundaries), reusing the existing `reorder`
output so the facade's reorder logic is untouched; new
adminCategories.moveUp/moveDown keys in en/ru/hy.
- Screen-reader loading announcements: skeleton-row loading states across
Products, Categories, Customers, Orders, Transactions, Users, Reviews,
Monitoring (webhooks/events), and Analytics (summary cards + top products)
were purely visual (app-skeleton is aria-hidden by design) with no
accessible "loading" text, unlike the storefront/product-details pattern -
added role="status"/aria-live="polite"/aria-busy + sr-only text using the
existing common.loading key.
- Table row headers: added scope="row" to the primary identifying cell
(product/category/customer name, order number, transaction order number,
user name, review customer, report target, top-products/low-stock product
name, webhook endpoint) on 9 tables that only had scope="col". Added
matching `tbody th[scope='row'] { font-weight/color/text-align/
vertical-align }` + last-row border resets in each component's own scss so
the semantic change doesn't alter visuals (the shared app-table stylesheet
styles all <th> as bold/muted by default).
Verified via `git show --stat` of fb1afb7/a03260e and `docs/UI-COMPOSITION-
REVIEW.md`'s Backoffice sections first, per instructions - confirmed
scope="col" coverage already complete, all admin modals already route
through the shared app-dialog (focus-trap/Escape/return-focus already
correct, nothing to fix), and the bare-<select> filters still carry
aria-label per the accepted Sprint 28 decision (not re-migrated to
app-select).
Flagged, not fixed:
- No toast/notification system exists anywhere in this codebase (product/
category save and delete call the gateway with no success/error UI at
all, not even a subscribe error handler) - there is nothing to wire
aria-live onto without adding a new UI mechanism, which is out of scope
for an a11y-only pass. A prerequisite feature-level fix, not an a11y
regression.
- Dashboard's per-card metric/status-row/timeline skeletons (dashboard-
metric, dashboard-status-row, dashboard-timeline) were left without
aria-live wiring - wrapping each of the ~10 simultaneous mini-widgets in
its own live region would fire a burst of redundant announcements; needs
a single page-level "loading dashboard" region instead, a larger change
than this surgical pass.
- Monitoring's events table and the notifications dropdown (role="menu"
with a static empty-state message, aria-haspopup="true") were left as-is -
matches the same partial-widget-pattern precedent already accepted for
locale-tabs/product-tabs in the storefront and builder passes.
- Analytics `lowStockProducts` table's missing loading-skeleton branch
(already flagged, not fixed, in the RC-Visual-02 pass) - untouched again
here for the same reason.
Verified: npx tsc --noEmit clean; npm run build green (only the pre-existing
768.57 kB vs 700 kB initial-bundle budget warning, unrelated to this pass).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 09:18:09 +04:00
|
|
|
moveUp: string;
|
|
|
|
|
moveDown: string;
|
2026-07-18 17:04:11 +04:00
|
|
|
jumpToParent: string;
|
|
|
|
|
deletedBadge: string;
|
|
|
|
|
column_slug: string;
|
|
|
|
|
column_items: string;
|
|
|
|
|
column_status: string;
|
|
|
|
|
column_visibility: string;
|
|
|
|
|
column_updated: string;
|
|
|
|
|
bulkAssignParent: string;
|
|
|
|
|
bulkAssignImage: string;
|
|
|
|
|
groupGeneral: string;
|
|
|
|
|
groupMedia: string;
|
|
|
|
|
groupSeo: string;
|
|
|
|
|
groupVisibility: string;
|
|
|
|
|
groupNavigation: string;
|
|
|
|
|
groupAttributes: string;
|
|
|
|
|
groupAdvanced: string;
|
|
|
|
|
visibilityExplain: string;
|
|
|
|
|
navBreadcrumb: string;
|
2026-07-19 08:35:18 +04:00
|
|
|
navBreadcrumbHint: string;
|
|
|
|
|
iconHint: string;
|
2026-07-18 17:04:11 +04:00
|
|
|
navRoot: string;
|
|
|
|
|
navChildren: string;
|
|
|
|
|
navNoChildren: string;
|
|
|
|
|
navAppearsIn: string;
|
|
|
|
|
navAppearsVisible: string;
|
|
|
|
|
navAppearsHidden: string;
|
|
|
|
|
itemsCountLabel: string;
|
|
|
|
|
createdAtLabel: string;
|
|
|
|
|
healthImage: string;
|
|
|
|
|
healthSeo: string;
|
|
|
|
|
healthDescription: string;
|
|
|
|
|
healthParent: string;
|
|
|
|
|
healthVisibility: string;
|
|
|
|
|
healthProducts: string;
|
|
|
|
|
totalCategories: string;
|
|
|
|
|
visibleCount: string;
|
|
|
|
|
hiddenCount: string;
|
|
|
|
|
emptyCount: string;
|
|
|
|
|
rootCount: string;
|
|
|
|
|
subCount: string;
|
|
|
|
|
missingImagesCount: string;
|
|
|
|
|
missingSeoCount: string;
|
|
|
|
|
lastModified: string;
|
|
|
|
|
lastModifiedNever: string;
|
|
|
|
|
completionLabel: string;
|
|
|
|
|
recommendedNext: string;
|
|
|
|
|
recommendAddImage: string;
|
|
|
|
|
recommendAddSeo: string;
|
|
|
|
|
recommendFillEmpty: string;
|
|
|
|
|
recommendNone: string;
|
fix(static-pages): backfill enabled/status in export, fix missing i18n key
Independent review pass over the Static Pages Module sprint (M1-M7),
including live browser E2E per the task's own verification checklist.
- ProjectEditorFacade.normalize() now backfills enabled/status on
record-format static pages (defaulting missing values to enabled+published,
same rule ContentPageService.normalizePage applies for display - mirrored
rather than imported, to avoid a project-editor <-> content-management
circular dependency since ContentManagementFacade already depends on this
facade). Found live: exporting a page that predates this sprint and was
never touched/re-saved in the current session produced JSON missing
enabled/status entirely - the editor UI and storefront resolver both
normalize-on-read so nothing was actually broken live, but Export/Import
fidelity should match what the editor shows. Verified fixed live (export
now includes "enabled":true,"status":"published" for an untouched legacy
page) and via the full gate.
- Added the missing adminCategories.chooseImage i18n key (interface +
en/ru/hy). Found live: the media-picker "choose image" button rendered as
the literal string "adminCategories.chooseImage" - a pre-existing,
repo-wide bug (5 templates reference this key; none of the locale files
ever defined it) that I propagated into a 3rd/4th/5th... well, 2 new
occurrences by copying the existing branding-section/footer-section
pattern into static-pages-editor. Fixed the actual defect (missing
translation) rather than renaming the key, which would have required
touching 2 unrelated admin components outside this sprint's scope.
Live-verified this pass: Static Pages editor renders with all new fields;
create page works (page count 4->confirmed); device preview toggles
desktop/tablet/mobile widths correctly; navigation "Insert page link"
creates a real type:'staticPage' nav item end-to-end (confirmed in the
exported JSON); export includes all Sprint X+2 fields after the fix; no
console errors throughout.
Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:27:29 +04:00
|
|
|
};
|
2026-07-16 00:19:41 +04:00
|
|
|
adminProducts: {
|
fix(admin): products canDeactivate guard, unblock npm, drop dead deps
RC-01 Phase 1 mechanical fixes (verified against current repo state,
not blindly reapplied from TODO.md):
- admin/products create/edit/duplicate now protected by an unsaved-
changes guard (adminProductDirtyGuard), mirroring the existing
categories pattern. AdminProductsFacade had zero dirty-tracking
before this - added a dirty signal, set true on updateDraft(),
cleared on load/create/successful save. Added confirmLeaveUnsaved
to the adminProducts i18n section (en/ru/hy) - categories already
had its own copy of this key, products didn't.
- barry-cache bumped ^0.1.0 -> ^0.9.3 (the pinned range no longer
resolved on the registry - ETARGET - which had been silently
blocking every npm install/uninstall all cycle).
- Removed primeng/primeicons (npm uninstall, now unblocked) - the
only consumer (items-carousel) was already deleted in RC PERF-01.
- Removed core/search/services/search-history.service.ts, a dead
1-line re-export with zero importers (verified: the real
implementation is features/search/services/search-history.service.ts,
used by search.facade.ts). Left core/search/models/* alone - those
ARE live, imported by catalog components.
Verified before touching: HeaderConfig.showProfile toggle is already
removed from the header-section editor template (TODO.md was stale on
this one) - no change needed, will correct the tracking doc separately.
tsc --noEmit clean, npm run build green (bundle unchanged, primeng
was already tree-shaken out, this just removes the dead dependency
declaration itself).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 20:04:51 +04:00
|
|
|
confirmLeaveUnsaved: string;
|
2026-07-16 00:19:41 +04:00
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyDescription: string;
|
feat(products): implement professional product management experience
Products dashboard (real total/published/drafts/out-of-stock/hidden/missing-images/missing-SEO/low-quality counts, recently-edited list, recommended next action); list gains table/grid view toggle, density, saved column visibility and saved sort (persisted via LocalStorageService), plus real bulk assign-category/assign-tags/duplicate/CSV-export alongside existing publish/hide/delete; per-row and per-editor reusable ProductHealthWidget (images/SEO/price/category/description/inventory checklist + completion %); editor reorganized into General/Media/Pricing/Inventory/Categories/Attributes/SEO/Visibility/Advanced tabs, media now uses the shared MediaPickerComponent/ImageFieldComponent (primary image + reorderable gallery) instead of raw URL textareas, specifications/attributes/variants moved off pipe-delimited textareas onto the shared KeyValueEditorComponent, SEO tab explains fields in plain language with a live search-result preview, inventory relabeled in business language, toggles/badges use the shared Toggle/Badge components. Filled in the adminProducts i18n namespace (previously ~98% missing, rendering raw translation keys) across en/ru/hy.
2026-07-18 16:34:06 +04:00
|
|
|
emptyGuide: string;
|
2026-07-19 23:55:11 +04:00
|
|
|
selectAllRows: string;
|
|
|
|
|
selectRow: string;
|
feat(products): implement professional product management experience
Products dashboard (real total/published/drafts/out-of-stock/hidden/missing-images/missing-SEO/low-quality counts, recently-edited list, recommended next action); list gains table/grid view toggle, density, saved column visibility and saved sort (persisted via LocalStorageService), plus real bulk assign-category/assign-tags/duplicate/CSV-export alongside existing publish/hide/delete; per-row and per-editor reusable ProductHealthWidget (images/SEO/price/category/description/inventory checklist + completion %); editor reorganized into General/Media/Pricing/Inventory/Categories/Attributes/SEO/Visibility/Advanced tabs, media now uses the shared MediaPickerComponent/ImageFieldComponent (primary image + reorderable gallery) instead of raw URL textareas, specifications/attributes/variants moved off pipe-delimited textareas onto the shared KeyValueEditorComponent, SEO tab explains fields in plain language with a live search-result preview, inventory relabeled in business language, toggles/badges use the shared Toggle/Badge components. Filled in the adminProducts i18n namespace (previously ~98% missing, rendering raw translation keys) across en/ru/hy.
2026-07-18 16:34:06 +04:00
|
|
|
search: string;
|
|
|
|
|
category: string;
|
|
|
|
|
allCategories: string;
|
|
|
|
|
visibility: string;
|
|
|
|
|
allVisibility: string;
|
|
|
|
|
visible: string;
|
|
|
|
|
hidden: string;
|
|
|
|
|
stockStatus: string;
|
|
|
|
|
allStock: string;
|
|
|
|
|
inStock: string;
|
|
|
|
|
lowStock: string;
|
|
|
|
|
outOfStock: string;
|
|
|
|
|
sortTitle: string;
|
|
|
|
|
sortPrice: string;
|
|
|
|
|
sortPriority: string;
|
|
|
|
|
sortStock: string;
|
|
|
|
|
sortUpdated: string;
|
|
|
|
|
showArchived: string;
|
|
|
|
|
infiniteScroll: string;
|
|
|
|
|
viewMode: string;
|
|
|
|
|
viewTable: string;
|
|
|
|
|
viewGrid: string;
|
|
|
|
|
density: string;
|
|
|
|
|
densityComfortable: string;
|
|
|
|
|
densityCompact: string;
|
|
|
|
|
columns: string;
|
|
|
|
|
column_sku: string;
|
|
|
|
|
column_brand: string;
|
|
|
|
|
column_price: string;
|
|
|
|
|
column_stock: string;
|
|
|
|
|
column_visibility: string;
|
|
|
|
|
column_updated: string;
|
|
|
|
|
create: string;
|
|
|
|
|
edit: string;
|
|
|
|
|
duplicate: string;
|
|
|
|
|
selectedCount: string;
|
|
|
|
|
bulkShow: string;
|
|
|
|
|
bulkHide: string;
|
|
|
|
|
bulkAssignCategory: string;
|
|
|
|
|
bulkAssignTags: string;
|
|
|
|
|
bulkDuplicateAction: string;
|
|
|
|
|
bulkExportAction: string;
|
|
|
|
|
bulkDelete: string;
|
|
|
|
|
tagsPlaceholder: string;
|
|
|
|
|
name: string;
|
|
|
|
|
brand: string;
|
|
|
|
|
healthColumn: string;
|
|
|
|
|
actions: string;
|
|
|
|
|
archive: string;
|
|
|
|
|
delete: string;
|
|
|
|
|
items: string;
|
|
|
|
|
loadMore: string;
|
|
|
|
|
noImage: string;
|
|
|
|
|
slug: string;
|
|
|
|
|
barcode: string;
|
|
|
|
|
priority: string;
|
|
|
|
|
shortDescription: string;
|
|
|
|
|
translations: string;
|
|
|
|
|
primaryImage: string;
|
|
|
|
|
primaryImageHint: string;
|
|
|
|
|
gallery: string;
|
|
|
|
|
galleryHint: string;
|
|
|
|
|
moveLeft: string;
|
|
|
|
|
moveRight: string;
|
|
|
|
|
videos: string;
|
|
|
|
|
discount: string;
|
|
|
|
|
currency: string;
|
|
|
|
|
stockQuantity: string;
|
|
|
|
|
stockQuantityHint: string;
|
|
|
|
|
availabilityStatus: string;
|
|
|
|
|
availabilityStatusHint: string;
|
|
|
|
|
availabilityNote: string;
|
|
|
|
|
availabilityNoteHint: string;
|
|
|
|
|
reservedNote: string;
|
|
|
|
|
relatedProducts: string;
|
|
|
|
|
specifications: string;
|
|
|
|
|
attributes: string;
|
|
|
|
|
addRow: string;
|
|
|
|
|
removeRow: string;
|
|
|
|
|
rowKey: string;
|
|
|
|
|
rowValue: string;
|
|
|
|
|
addVariant: string;
|
|
|
|
|
variantName: string;
|
|
|
|
|
variantsHint: string;
|
2026-07-18 22:44:39 +04:00
|
|
|
variants: string;
|
feat(admin): Shopify-style variant attributes matching production data shape
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P0 user feedback: variants were just free-text name+price, and the user shared the real production payload - a flat array of {color, size, price, currency, remaining} rows, colors as '0x8B4513' hex.
- New model: AdminProductVariantAttributeDef (key/label/isColor/values) + AdminProductVariant (attributes: Record<string,string>, sku, image, remaining, prices: {currency,price}[]) - this IS the production shape, grouped by combo with one row per currency instead of flattened, so admins edit one variant card instead of 4 duplicate rows
- Attribute manager: add custom attributes (Color, Size, or anything), color attributes get a native color picker + live swatch preview instead of typing hex; other attributes get plain value chips
- 'Generate variants' computes the cartesian product of attribute values (Color x Size = 4 combos for 1 color x 4 sizes) and preserves existing sku/price/stock data for combos that still exist after regeneration
- Multi-currency pricing per variant (matches prod: same combo priced in RUB/USD/EUR/AMD) with per-currency add/remove
- Color hex kept in the exact '0x8B4513' production format (toBackendColor/toCssColor conversion helpers)
- Fixed an Angular v21 control-flow parser bug hit while building this: an @if/@else block whose only content is a bare {{ interpolation }} touching the block's closing brace fails to parse (NG5002 'Unclosed block for' cascading from a completely unrelated line) - worked around by keeping interpolation in its own element
- Verified end-to-end in browser: added Color (color picker) + Size (S/M/L/XL) attributes, generated 4 variant combos, added all 4 currencies to a variant - matches the shared production JSON exactly
2026-07-19 13:40:51 +04:00
|
|
|
variantAttributes: string;
|
|
|
|
|
variantAttributesHint: string;
|
|
|
|
|
colorAttribute: string;
|
|
|
|
|
removeAttribute: string;
|
|
|
|
|
removeValue: string;
|
|
|
|
|
pickColor: string;
|
|
|
|
|
newValuePlaceholder: string;
|
|
|
|
|
addValue: string;
|
|
|
|
|
newAttributePlaceholder: string;
|
|
|
|
|
addAttribute: string;
|
|
|
|
|
generateVariants: string;
|
|
|
|
|
variantsList: string;
|
|
|
|
|
remaining: string;
|
|
|
|
|
variantImage: string;
|
2026-07-18 22:44:39 +04:00
|
|
|
archived: string;
|
feat(admin): product editor auto-slug, SKU helper, one-click SEO fill
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P0 user feedback: admins did not know what SKU means, had to hand-write slugs, and left SEO empty.
- Name edits now derive the URL slug automatically (supports Cyrillic/Armenian characters); the derivation stops the moment the slug no longer matches the auto value, so a manually edited slug is never overwritten - verified in browser
- SEO title mirrors the name under the same only-while-untouched rule
- SKU field explains itself (what a stock keeping unit is, that any unique text works) and gains a Generate button producing readable codes like WIR-GAM-7K2P from the product name
- SEO tab gains 'Fill from product details': fills only empty title/description/keywords from name and short description, existing text untouched
- New adminProducts keys (slugHint, skuHint, generate, seoGenerate, seoGenerateHint) in en/ru/hy
2026-07-19 08:30:49 +04:00
|
|
|
slugHint: string;
|
|
|
|
|
skuHint: string;
|
|
|
|
|
generate: string;
|
|
|
|
|
seoGenerate: string;
|
|
|
|
|
seoGenerateHint: string;
|
2026-07-19 08:40:30 +04:00
|
|
|
translationsHint: string;
|
2026-07-19 08:44:20 +04:00
|
|
|
badgesHint: string;
|
|
|
|
|
addBadge: string;
|
|
|
|
|
removeBadge: string;
|
|
|
|
|
customBadgePlaceholder: string;
|
feat(products): implement professional product management experience
Products dashboard (real total/published/drafts/out-of-stock/hidden/missing-images/missing-SEO/low-quality counts, recently-edited list, recommended next action); list gains table/grid view toggle, density, saved column visibility and saved sort (persisted via LocalStorageService), plus real bulk assign-category/assign-tags/duplicate/CSV-export alongside existing publish/hide/delete; per-row and per-editor reusable ProductHealthWidget (images/SEO/price/category/description/inventory checklist + completion %); editor reorganized into General/Media/Pricing/Inventory/Categories/Attributes/SEO/Visibility/Advanced tabs, media now uses the shared MediaPickerComponent/ImageFieldComponent (primary image + reorderable gallery) instead of raw URL textareas, specifications/attributes/variants moved off pipe-delimited textareas onto the shared KeyValueEditorComponent, SEO tab explains fields in plain language with a live search-result preview, inventory relabeled in business language, toggles/badges use the shared Toggle/Badge components. Filled in the adminProducts i18n namespace (previously ~98% missing, rendering raw translation keys) across en/ru/hy.
2026-07-18 16:34:06 +04:00
|
|
|
seoExplain: string;
|
|
|
|
|
searchTitle: string;
|
|
|
|
|
searchTitleHint: string;
|
|
|
|
|
searchDescription: string;
|
|
|
|
|
searchDescriptionHint: string;
|
|
|
|
|
seoMissingTitle: string;
|
|
|
|
|
seoMissingDescription: string;
|
|
|
|
|
keywords: string;
|
|
|
|
|
featured: string;
|
|
|
|
|
recommended: string;
|
|
|
|
|
new: string;
|
|
|
|
|
bestseller: string;
|
|
|
|
|
badges: string;
|
|
|
|
|
htmlDescription: string;
|
|
|
|
|
customer: string;
|
|
|
|
|
reviewsReadonly: string;
|
|
|
|
|
noReviews: string;
|
|
|
|
|
questionsReadonly: string;
|
|
|
|
|
noQuestions: string;
|
|
|
|
|
save: string;
|
|
|
|
|
groupGeneral: string;
|
|
|
|
|
groupMedia: string;
|
|
|
|
|
groupPricing: string;
|
|
|
|
|
groupInventory: string;
|
|
|
|
|
groupCategories: string;
|
|
|
|
|
groupAttributes: string;
|
|
|
|
|
groupSeo: string;
|
|
|
|
|
groupVisibility: string;
|
|
|
|
|
groupAdvanced: string;
|
|
|
|
|
healthImages: string;
|
|
|
|
|
healthSeo: string;
|
|
|
|
|
healthPrice: string;
|
|
|
|
|
healthCategory: string;
|
|
|
|
|
healthDescription: string;
|
|
|
|
|
healthInventory: string;
|
|
|
|
|
totalProducts: string;
|
|
|
|
|
publishedCount: string;
|
|
|
|
|
draftsCount: string;
|
|
|
|
|
outOfStockCount: string;
|
|
|
|
|
hiddenCount: string;
|
|
|
|
|
missingImagesCount: string;
|
|
|
|
|
missingSeoCount: string;
|
|
|
|
|
lowQualityCount: string;
|
|
|
|
|
recentlyEdited: string;
|
|
|
|
|
recommendedNext: string;
|
|
|
|
|
openAction: string;
|
|
|
|
|
recommendAddImages: string;
|
|
|
|
|
recommendAddSeo: string;
|
|
|
|
|
recommendRestock: string;
|
|
|
|
|
recommendNone: string;
|
2026-07-16 00:19:41 +04:00
|
|
|
};
|
|
|
|
|
adminUsers: {
|
|
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyDescription: string;
|
|
|
|
|
invitationsEmptyTitle: string;
|
2026-07-18 22:44:39 +04:00
|
|
|
title: string;
|
|
|
|
|
name: string;
|
|
|
|
|
email: string;
|
|
|
|
|
scope: string;
|
|
|
|
|
role: string;
|
|
|
|
|
roles: string;
|
|
|
|
|
lastLogin: string;
|
|
|
|
|
sessions: string;
|
|
|
|
|
currentSession: string;
|
|
|
|
|
invite: string;
|
|
|
|
|
sendInvite: string;
|
|
|
|
|
revoke: string;
|
|
|
|
|
passwordlessHint: string;
|
|
|
|
|
confirmSuspend: string;
|
2026-07-19 23:04:51 +04:00
|
|
|
suspend: string;
|
|
|
|
|
reactivate: string;
|
2026-07-18 22:44:39 +04:00
|
|
|
scopeValue: {
|
|
|
|
|
marketplace: string;
|
|
|
|
|
office: string;
|
|
|
|
|
};
|
|
|
|
|
statusValue: {
|
|
|
|
|
active: string;
|
|
|
|
|
invited: string;
|
|
|
|
|
suspended: string;
|
|
|
|
|
};
|
|
|
|
|
invitationStatus: {
|
|
|
|
|
pending: string;
|
|
|
|
|
accepted: string;
|
|
|
|
|
expired: string;
|
|
|
|
|
revoked: string;
|
|
|
|
|
};
|
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
|
|
|
roleValue: {
|
|
|
|
|
owner: string;
|
|
|
|
|
admin: string;
|
|
|
|
|
editor: string;
|
|
|
|
|
viewer: string;
|
|
|
|
|
};
|
|
|
|
|
permission: {
|
|
|
|
|
all: string;
|
|
|
|
|
productsManage: string;
|
|
|
|
|
productsView: string;
|
|
|
|
|
categoriesManage: string;
|
|
|
|
|
ordersManage: string;
|
|
|
|
|
ordersView: string;
|
|
|
|
|
mediaManage: string;
|
|
|
|
|
};
|
|
|
|
|
actor: {
|
|
|
|
|
admin: string;
|
|
|
|
|
};
|
|
|
|
|
audit: {
|
|
|
|
|
roleChanged: string;
|
|
|
|
|
statusChanged: string;
|
|
|
|
|
};
|
2026-07-18 22:44:39 +04:00
|
|
|
};
|
|
|
|
|
adminTransactions: {
|
|
|
|
|
search: string;
|
|
|
|
|
type: string;
|
|
|
|
|
method: string;
|
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
|
|
|
itemsCount: string;
|
2026-07-18 22:44:39 +04:00
|
|
|
fraud: string;
|
|
|
|
|
flagged: string;
|
2026-07-19 08:25:29 +04:00
|
|
|
flag: string;
|
|
|
|
|
clearFlag: string;
|
2026-07-18 22:44:39 +04:00
|
|
|
retry: string;
|
|
|
|
|
audit: string;
|
|
|
|
|
emptyTitle: string;
|
|
|
|
|
emptyDescription: string;
|
|
|
|
|
status: {
|
|
|
|
|
all: string;
|
|
|
|
|
pending: string;
|
|
|
|
|
success: string;
|
|
|
|
|
failed: string;
|
|
|
|
|
retried: string;
|
|
|
|
|
};
|
|
|
|
|
typeValue: {
|
|
|
|
|
all: string;
|
|
|
|
|
payment: string;
|
|
|
|
|
refund: string;
|
|
|
|
|
qr_payment: string;
|
|
|
|
|
};
|
fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
review moderation events, user role/status changes) with proper
adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
adminUsers.permission.*), replacing developer-facing enum leakage with
real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
list pages all reused adminProducts.items ("N товаров"/"N products")
regardless of what was actually listed; each now has its own itemsCount
key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
of the above.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
|
|
|
methodValue: {
|
|
|
|
|
card: string;
|
|
|
|
|
qr: string;
|
|
|
|
|
cash_on_delivery: string;
|
|
|
|
|
};
|
2026-07-16 00:19:41 +04:00
|
|
|
};
|
|
|
|
|
adminMonitoring: {
|
|
|
|
|
eventsEmptyTitle: string;
|
|
|
|
|
eventsEmptyDescription: string;
|
2026-07-18 22:44:39 +04:00
|
|
|
health: string;
|
|
|
|
|
queues: string;
|
|
|
|
|
depth: string;
|
|
|
|
|
webhooks: string;
|
|
|
|
|
endpoint: string;
|
|
|
|
|
event: string;
|
|
|
|
|
events: string;
|
|
|
|
|
category: string;
|
|
|
|
|
level: string;
|
|
|
|
|
message: string;
|
2026-07-26 00:17:14 +04:00
|
|
|
technicalDetails: string;
|
2026-07-18 22:44:39 +04:00
|
|
|
categoryValue: {
|
|
|
|
|
all: string;
|
|
|
|
|
audit: string;
|
|
|
|
|
security: string;
|
|
|
|
|
login: string;
|
|
|
|
|
failed_login: string;
|
|
|
|
|
api: string;
|
|
|
|
|
error: string;
|
|
|
|
|
warning: string;
|
|
|
|
|
};
|
|
|
|
|
queueStatus: {
|
|
|
|
|
healthy: string;
|
|
|
|
|
degraded: string;
|
|
|
|
|
down: string;
|
|
|
|
|
};
|
|
|
|
|
webhookStatus: {
|
|
|
|
|
delivered: string;
|
|
|
|
|
failed: string;
|
|
|
|
|
pending: string;
|
|
|
|
|
};
|
|
|
|
|
levelValue: {
|
|
|
|
|
info: string;
|
|
|
|
|
warning: string;
|
|
|
|
|
error: string;
|
|
|
|
|
};
|
feat(admin): implement analytics and monitoring center
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Business Dashboard: revenue/orders/customers/AOV/top products/low stock/recent activity/warnings/completion% (Overview tab)
- Marketplace Health: real completion checks (images, SEO, categories, reviews, orders, translations, homepage, backend, performance) with clickable recommendations
- Product Analytics: top selling/most reviewed/worst rated/hidden/archived counts; top-viewed honestly marked Unknown (no view tracking exists)
- Customer Analytics: new/returning customers, average spend, retention - derived from real order data
- Search & Traffic tabs: honest 'Unknown - available after backend integration' placeholders, no fabricated numbers
- Recommendations engine: actionable cards (missing images/SEO/category, empty categories, incomplete homepage, unpublished static pages) linking to the relevant admin page
- System Monitoring: added real draft/publish/sync/backend-connectivity state from AdminDashboardFacade
- CSV export extended to top products and health checks; added print action
- New adminAnalytics.* and adminMarketplaceHealth.* i18n namespaces (en/ru/hy), no raw i18n keys
- Reused existing shared UI (app-table/app-badge/app-skeleton/app-empty-state) and content-health-widget completion-meter pattern - no new backend APIs, no storage changes
2026-07-18 22:33:36 +04:00
|
|
|
systemState: string;
|
|
|
|
|
backendConnectivity: string;
|
|
|
|
|
connected: string;
|
|
|
|
|
loading: string;
|
|
|
|
|
draftState: string;
|
|
|
|
|
unsavedChanges: string;
|
|
|
|
|
noDraft: string;
|
|
|
|
|
lastSaved: string;
|
|
|
|
|
lastPublished: string;
|
|
|
|
|
syncStatus: string;
|
2026-07-16 00:19:41 +04:00
|
|
|
};
|
feat: close stub-page gaps - profile login/logout, admin Reports/Settings, Help/Docs links
Sprint A: storefront header profile control (login/logout only, no menu),
wired to existing customer Telegram auth (AuthService).
Sprint B: backoffice/reports page, reuses AdminAnalyticsFacade (Sales,
Top Products, Marketplace Health cards + CSV export).
Sprint C: backoffice/settings page, admin UI density preference
(comfortable/compact), localStorage-persisted, applied to app-table
across all admin list pages.
Sprint D: admin bottom-nav Help -> mailto using existing supportEmail,
Documentation -> external link via new TenantConfig.documentationUrl.
AdminNavLink gains externalHref for non-routerLink nav entries.
Docs: docs/GLOBAL-SPRINT-PLAN.md tracks the full sprint breakdown.
docs/COMING-SOON-AUDIT.md removed, folded into docs/KNOWN-ISSUES.md.
docs/BACKEND.md updated with the new documentationUrl bootstrap field.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 17:48:50 +04:00
|
|
|
adminReports: {
|
|
|
|
|
sales: string;
|
|
|
|
|
topProducts: string;
|
|
|
|
|
marketplaceHealth: string;
|
|
|
|
|
};
|
|
|
|
|
adminSettings: {
|
|
|
|
|
density: string;
|
|
|
|
|
densityExplain: string;
|
|
|
|
|
densityCompact: string;
|
|
|
|
|
};
|
2026-07-16 00:19:41 +04:00
|
|
|
adminAnalytics: {
|
|
|
|
|
topProductsEmptyTitle: string;
|
|
|
|
|
topProductsEmptyDescription: string;
|
2026-07-18 22:44:39 +04:00
|
|
|
topProducts: string;
|
feat(admin): implement analytics and monitoring center
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Business Dashboard: revenue/orders/customers/AOV/top products/low stock/recent activity/warnings/completion% (Overview tab)
- Marketplace Health: real completion checks (images, SEO, categories, reviews, orders, translations, homepage, backend, performance) with clickable recommendations
- Product Analytics: top selling/most reviewed/worst rated/hidden/archived counts; top-viewed honestly marked Unknown (no view tracking exists)
- Customer Analytics: new/returning customers, average spend, retention - derived from real order data
- Search & Traffic tabs: honest 'Unknown - available after backend integration' placeholders, no fabricated numbers
- Recommendations engine: actionable cards (missing images/SEO/category, empty categories, incomplete homepage, unpublished static pages) linking to the relevant admin page
- System Monitoring: added real draft/publish/sync/backend-connectivity state from AdminDashboardFacade
- CSV export extended to top products and health checks; added print action
- New adminAnalytics.* and adminMarketplaceHealth.* i18n namespaces (en/ru/hy), no raw i18n keys
- Reused existing shared UI (app-table/app-badge/app-skeleton/app-empty-state) and content-health-widget completion-meter pattern - no new backend APIs, no storage changes
2026-07-18 22:33:36 +04:00
|
|
|
print: string;
|
|
|
|
|
tabsLabel: string;
|
|
|
|
|
tab: {
|
|
|
|
|
overview: string;
|
|
|
|
|
health: string;
|
|
|
|
|
products: string;
|
|
|
|
|
customers: string;
|
|
|
|
|
search: string;
|
|
|
|
|
traffic: string;
|
|
|
|
|
recommendations: string;
|
|
|
|
|
};
|
|
|
|
|
revenue: string;
|
|
|
|
|
orders: string;
|
|
|
|
|
customers: string;
|
|
|
|
|
avgOrderValue: string;
|
|
|
|
|
conversion: string;
|
|
|
|
|
completionPercent: string;
|
|
|
|
|
unknown: string;
|
|
|
|
|
salesChart: string;
|
|
|
|
|
quantitySold: string;
|
|
|
|
|
lowStock: string;
|
|
|
|
|
lowStockEmptyTitle: string;
|
|
|
|
|
quantity: string;
|
|
|
|
|
status: string;
|
|
|
|
|
recentActivity: string;
|
|
|
|
|
recentActivityEmptyTitle: string;
|
|
|
|
|
activityDraftSaved: string;
|
|
|
|
|
activityPublished: string;
|
|
|
|
|
warnings: string;
|
|
|
|
|
topViewed: string;
|
|
|
|
|
hiddenProducts: string;
|
|
|
|
|
archivedProducts: string;
|
|
|
|
|
mostReviewed: string;
|
|
|
|
|
worstRated: string;
|
|
|
|
|
noReviewedProducts: string;
|
|
|
|
|
reviewCount: string;
|
|
|
|
|
avgRating: string;
|
|
|
|
|
newCustomers: string;
|
|
|
|
|
returningCustomers: string;
|
|
|
|
|
averageSpend: string;
|
|
|
|
|
retention: string;
|
|
|
|
|
searchAnalytics: string;
|
|
|
|
|
trafficAnalytics: string;
|
|
|
|
|
availableAfterBackend: string;
|
|
|
|
|
pendingBackend: string;
|
|
|
|
|
pendingBackendHint: string;
|
|
|
|
|
funnelsHeatmaps: string;
|
|
|
|
|
visitors: string;
|
|
|
|
|
products: string;
|
|
|
|
|
categories: string;
|
|
|
|
|
};
|
|
|
|
|
adminMarketplaceHealth: {
|
|
|
|
|
title: string;
|
|
|
|
|
complete: string;
|
|
|
|
|
recommendationsTitle: string;
|
|
|
|
|
recommendNone: string;
|
|
|
|
|
checkImages: string;
|
|
|
|
|
checkSeo: string;
|
|
|
|
|
checkCategories: string;
|
|
|
|
|
checkReviews: string;
|
|
|
|
|
checkOrders: string;
|
|
|
|
|
checkTranslations: string;
|
|
|
|
|
checkHomepage: string;
|
|
|
|
|
checkBackend: string;
|
|
|
|
|
checkPerformance: string;
|
|
|
|
|
recommendImages: string;
|
|
|
|
|
recommendImagesCount: string;
|
|
|
|
|
recommendSeo: string;
|
|
|
|
|
recommendSeoCount: string;
|
|
|
|
|
recommendCategory: string;
|
|
|
|
|
recommendCategoryCount: string;
|
|
|
|
|
recommendEmptyCategories: string;
|
|
|
|
|
recommendEmptyCategoriesCount: string;
|
|
|
|
|
recommendHomepage: string;
|
|
|
|
|
recommendStaticPages: string;
|
|
|
|
|
severity: {
|
|
|
|
|
info: string;
|
|
|
|
|
warning: string;
|
|
|
|
|
critical: string;
|
|
|
|
|
};
|
2026-07-16 00:19:41 +04:00
|
|
|
};
|
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
|
|
|
adminShell: {
|
|
|
|
|
skipToContent: string;
|
fix(backoffice): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, Backoffice (admin/*) area. Builds on 712a7b4/63c9cee's
composition pass (scope="col", skeletons, empty-states) without redoing that
work.
- Sidebar nav landmark: admin-layout's <nav aria-label> reused the
"Dashboard" nav-item translation key as its landmark label, misleadingly
announcing the whole sidebar as "Dashboard" - added a dedicated
adminShell.sidebarLabel key ("Admin sidebar navigation") in en/ru/hy.
Skip link, #admin-content main landmark, Escape handling, and mobile-drawer
focus management were already correct - verified, not touched.
- Categories tree drag-and-drop keyboard fallback (WCAG 2.1.1): the category
tree's native HTML5 DnD (draggable/dragstart/drop) reorders siblings with
no keyboard equivalent - existing arrow-key tree navigation only expands/
collapses/selects, never reorders. Added per-row move-up/move-down icon
buttons (disabled at sibling boundaries), reusing the existing `reorder`
output so the facade's reorder logic is untouched; new
adminCategories.moveUp/moveDown keys in en/ru/hy.
- Screen-reader loading announcements: skeleton-row loading states across
Products, Categories, Customers, Orders, Transactions, Users, Reviews,
Monitoring (webhooks/events), and Analytics (summary cards + top products)
were purely visual (app-skeleton is aria-hidden by design) with no
accessible "loading" text, unlike the storefront/product-details pattern -
added role="status"/aria-live="polite"/aria-busy + sr-only text using the
existing common.loading key.
- Table row headers: added scope="row" to the primary identifying cell
(product/category/customer name, order number, transaction order number,
user name, review customer, report target, top-products/low-stock product
name, webhook endpoint) on 9 tables that only had scope="col". Added
matching `tbody th[scope='row'] { font-weight/color/text-align/
vertical-align }` + last-row border resets in each component's own scss so
the semantic change doesn't alter visuals (the shared app-table stylesheet
styles all <th> as bold/muted by default).
Verified via `git show --stat` of fb1afb7/a03260e and `docs/UI-COMPOSITION-
REVIEW.md`'s Backoffice sections first, per instructions - confirmed
scope="col" coverage already complete, all admin modals already route
through the shared app-dialog (focus-trap/Escape/return-focus already
correct, nothing to fix), and the bare-<select> filters still carry
aria-label per the accepted Sprint 28 decision (not re-migrated to
app-select).
Flagged, not fixed:
- No toast/notification system exists anywhere in this codebase (product/
category save and delete call the gateway with no success/error UI at
all, not even a subscribe error handler) - there is nothing to wire
aria-live onto without adding a new UI mechanism, which is out of scope
for an a11y-only pass. A prerequisite feature-level fix, not an a11y
regression.
- Dashboard's per-card metric/status-row/timeline skeletons (dashboard-
metric, dashboard-status-row, dashboard-timeline) were left without
aria-live wiring - wrapping each of the ~10 simultaneous mini-widgets in
its own live region would fire a burst of redundant announcements; needs
a single page-level "loading dashboard" region instead, a larger change
than this surgical pass.
- Monitoring's events table and the notifications dropdown (role="menu"
with a static empty-state message, aria-haspopup="true") were left as-is -
matches the same partial-widget-pattern precedent already accepted for
locale-tabs/product-tabs in the storefront and builder passes.
- Analytics `lowStockProducts` table's missing loading-skeleton branch
(already flagged, not fixed, in the RC-Visual-02 pass) - untouched again
here for the same reason.
Verified: npx tsc --noEmit clean; npm run build green (only the pre-existing
768.57 kB vs 700 kB initial-bundle budget warning, unrelated to this pass).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 09:18:09 +04:00
|
|
|
sidebarLabel: string;
|
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
|
|
|
openSidebar: string;
|
|
|
|
|
closeSidebar: string;
|
|
|
|
|
collapseSidebar: string;
|
|
|
|
|
expandSidebar: string;
|
|
|
|
|
nav: {
|
|
|
|
|
dashboard: string;
|
|
|
|
|
catalogGroup: string;
|
|
|
|
|
products: string;
|
|
|
|
|
categories: string;
|
|
|
|
|
orders: string;
|
2026-07-18 21:47:54 +04:00
|
|
|
customers: string;
|
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
|
|
|
transactions: string;
|
|
|
|
|
reviews: string;
|
feat(admin): implement review and moderation center
New Reviews & Moderation feature (frontend only): moderation dashboard (real pending/approved/rejected/reported/spam counts, average rating, recent activity, moderation-health%, computed from the full review queue); reviews list with table/cards, density, saved column visibility, search/status/rating filters, bulk approve/reject/spam/hide/export; review detail shows customer/product/rating/text/photos/timeline/moderator-notes with a real moderation workflow (approve/reject/spam/hide/restore/pin/feature, feature disabled with an explanation unless the review is approved); reusable ReviewHealthWidget (rating/text/media/moderated/report-status/visible + completion%); reports queue lists reports against products/reviews/customers/categories with resolve/dismiss, and honestly renders 'Not available yet' rather than fabricating a value wherever a target can't be resolved (e.g. photos, customer-target reports). Backed by a new in-memory AdminModerationLocalGateway seeded from real product data - the same mock-gateway pattern already used by every other admin feature in this app (orders/products/categories), since no review/report backend exists to reuse. Replaced the 'Reviews' comingSoon nav placeholder with a working link; added full adminModeration i18n coverage.
2026-07-18 22:01:16 +04:00
|
|
|
moderation: string;
|
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
|
|
|
reports: string;
|
feat(admin): Seller Management Phase 1 UI - Partners section, empty state, request/learn-more dialogs
No backend, no CRUD, no API, no business logic - production-quality
UI only, built entirely from existing shared components (app-dialog,
app-empty-state, app-button, app-form-field, app-input, app-icon,
app-badge). Gated per ADR-011: reads
modules.sellerManagement.enabled from bootstrap (always false today,
no backend sets it) rather than hardcoding disabled state.
New:
- AdminSellerManagementPageComponent (features/admin/seller-management/
pages/) - renders the specified empty state (title/description/
Request Access + Learn More buttons) using existing shared/ui
primitives only, no new UI infrastructure.
- Request Access dialog: Company/Email/Message form via
app-form-field + app-input + a plain textarea (no dedicated
textarea component exists yet, styled to match app-input's own
tokens exactly). Submission is mocked (setTimeout), no API call.
On submit: closes and opens a success dialog ("Thank you...").
- Learn More dialog: 6 capability bullets (seller dashboards,
storefronts, permissions, analytics, product ownership, marketplace
administration) under a "Coming Soon" badge.
- New admin nav group "Partners" > "Seller Management" link
(admin-nav.model.ts), new route /backoffice/partners/seller-management
(app.routes.ts), using the same loadComponent/breadcrumb pattern as
every other admin route.
Translations: full en/ru/hy coverage, zero hardcoded strings - new
adminShell.nav.{partnersGroup,sellerManagement},
adminShell.pages.sellerManagement, and a new adminSellerManagement.*
namespace (emptyState/requestDialog/requestSuccessDialog/
learnMoreDialog) added to translations.ts (types) and all three
locale files.
Accessibility: inherited from app-dialog (role="dialog",
aria-modal, focus trap on Tab/Shift+Tab, Escape to close, focus
restored to trigger on close) - no new a11y code needed, reused as-is.
Responsive: existing --space-*/--font-size-* tokens throughout,
flex-wrap on button row, mobile breakpoint stacks actions full-width.
Verified live (ru locale, devBypassAdmin): nav group/link render
correctly, breadcrumb shows "Управление продавцами", empty state
copy matches spec exactly, Request Access dialog opens with all 3
fields + Cancel/Send Request, filled + submitted -> success dialog
with exact spec copy, Learn More dialog shows all 6 bullets + Coming
Soon badge, no console errors, verified again at 375px mobile
viewport. tsc --noEmit clean, ng build clean (pre-existing bundle-
budget warning only), arch:check (boundaries + cycles) clean.
2026-07-26 20:47:18 +04:00
|
|
|
partnersGroup: string;
|
|
|
|
|
sellerManagement: string;
|
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
|
|
|
content: string;
|
|
|
|
|
mediaLibrary: string;
|
|
|
|
|
marketplaceBuilder: string;
|
|
|
|
|
users: string;
|
|
|
|
|
settings: string;
|
|
|
|
|
monitoring: string;
|
|
|
|
|
analytics: string;
|
|
|
|
|
documentation: string;
|
|
|
|
|
help: string;
|
|
|
|
|
logout: string;
|
|
|
|
|
comingSoonBadge: string;
|
|
|
|
|
};
|
|
|
|
|
topbar: {
|
|
|
|
|
searchLabel: string;
|
|
|
|
|
searchPlaceholder: string;
|
|
|
|
|
notifications: string;
|
|
|
|
|
notificationsEmpty: string;
|
|
|
|
|
account: string;
|
|
|
|
|
tenantSelector: string;
|
|
|
|
|
tenantSelectorComingSoon: string;
|
|
|
|
|
quickPublish: string;
|
|
|
|
|
quickPublishComingSoon: string;
|
|
|
|
|
};
|
|
|
|
|
breadcrumbHome: string;
|
|
|
|
|
pages: {
|
|
|
|
|
dashboard: { title: string; description: string };
|
|
|
|
|
products: { title: string; description: string };
|
|
|
|
|
productCreate: { title: string; description: string };
|
|
|
|
|
productEdit: { title: string; description: string };
|
|
|
|
|
productDuplicate: { title: string; description: string };
|
|
|
|
|
categories: { title: string; description: string };
|
|
|
|
|
categoryCreate: { title: string; description: string };
|
|
|
|
|
categoryEdit: { title: string; description: string };
|
|
|
|
|
orders: { title: string; description: string };
|
|
|
|
|
orderDetail: { title: string; description: string };
|
2026-07-18 21:47:54 +04:00
|
|
|
customers: { title: string; description: string };
|
|
|
|
|
customerDetail: { title: string; description: string };
|
feat(admin): implement review and moderation center
New Reviews & Moderation feature (frontend only): moderation dashboard (real pending/approved/rejected/reported/spam counts, average rating, recent activity, moderation-health%, computed from the full review queue); reviews list with table/cards, density, saved column visibility, search/status/rating filters, bulk approve/reject/spam/hide/export; review detail shows customer/product/rating/text/photos/timeline/moderator-notes with a real moderation workflow (approve/reject/spam/hide/restore/pin/feature, feature disabled with an explanation unless the review is approved); reusable ReviewHealthWidget (rating/text/media/moderated/report-status/visible + completion%); reports queue lists reports against products/reviews/customers/categories with resolve/dismiss, and honestly renders 'Not available yet' rather than fabricating a value wherever a target can't be resolved (e.g. photos, customer-target reports). Backed by a new in-memory AdminModerationLocalGateway seeded from real product data - the same mock-gateway pattern already used by every other admin feature in this app (orders/products/categories), since no review/report backend exists to reuse. Replaced the 'Reviews' comingSoon nav placeholder with a working link; added full adminModeration i18n coverage.
2026-07-18 22:01:16 +04:00
|
|
|
moderation: { title: string; description: string };
|
|
|
|
|
reviewDetail: { title: string; description: string };
|
|
|
|
|
reportsQueue: { title: string; description: string };
|
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
|
|
|
transactions: { title: string; description: string };
|
|
|
|
|
media: { title: string; description: string };
|
|
|
|
|
users: { title: string; description: string };
|
|
|
|
|
monitoring: { title: string; description: string };
|
|
|
|
|
analytics: { title: string; description: string };
|
feat(admin): Seller Management Phase 1 UI - Partners section, empty state, request/learn-more dialogs
No backend, no CRUD, no API, no business logic - production-quality
UI only, built entirely from existing shared components (app-dialog,
app-empty-state, app-button, app-form-field, app-input, app-icon,
app-badge). Gated per ADR-011: reads
modules.sellerManagement.enabled from bootstrap (always false today,
no backend sets it) rather than hardcoding disabled state.
New:
- AdminSellerManagementPageComponent (features/admin/seller-management/
pages/) - renders the specified empty state (title/description/
Request Access + Learn More buttons) using existing shared/ui
primitives only, no new UI infrastructure.
- Request Access dialog: Company/Email/Message form via
app-form-field + app-input + a plain textarea (no dedicated
textarea component exists yet, styled to match app-input's own
tokens exactly). Submission is mocked (setTimeout), no API call.
On submit: closes and opens a success dialog ("Thank you...").
- Learn More dialog: 6 capability bullets (seller dashboards,
storefronts, permissions, analytics, product ownership, marketplace
administration) under a "Coming Soon" badge.
- New admin nav group "Partners" > "Seller Management" link
(admin-nav.model.ts), new route /backoffice/partners/seller-management
(app.routes.ts), using the same loadComponent/breadcrumb pattern as
every other admin route.
Translations: full en/ru/hy coverage, zero hardcoded strings - new
adminShell.nav.{partnersGroup,sellerManagement},
adminShell.pages.sellerManagement, and a new adminSellerManagement.*
namespace (emptyState/requestDialog/requestSuccessDialog/
learnMoreDialog) added to translations.ts (types) and all three
locale files.
Accessibility: inherited from app-dialog (role="dialog",
aria-modal, focus trap on Tab/Shift+Tab, Escape to close, focus
restored to trigger on close) - no new a11y code needed, reused as-is.
Responsive: existing --space-*/--font-size-* tokens throughout,
flex-wrap on button row, mobile breakpoint stacks actions full-width.
Verified live (ru locale, devBypassAdmin): nav group/link render
correctly, breadcrumb shows "Управление продавцами", empty state
copy matches spec exactly, Request Access dialog opens with all 3
fields + Cancel/Send Request, filled + submitted -> success dialog
with exact spec copy, Learn More dialog shows all 6 bullets + Coming
Soon badge, no console errors, verified again at 375px mobile
viewport. tsc --noEmit clean, ng build clean (pre-existing bundle-
budget warning only), arch:check (boundaries + cycles) clean.
2026-07-26 20:47:18 +04:00
|
|
|
sellerManagement: { title: string; description: string };
|
feat: close stub-page gaps - profile login/logout, admin Reports/Settings, Help/Docs links
Sprint A: storefront header profile control (login/logout only, no menu),
wired to existing customer Telegram auth (AuthService).
Sprint B: backoffice/reports page, reuses AdminAnalyticsFacade (Sales,
Top Products, Marketplace Health cards + CSV export).
Sprint C: backoffice/settings page, admin UI density preference
(comfortable/compact), localStorage-persisted, applied to app-table
across all admin list pages.
Sprint D: admin bottom-nav Help -> mailto using existing supportEmail,
Documentation -> external link via new TenantConfig.documentationUrl.
AdminNavLink gains externalHref for non-routerLink nav entries.
Docs: docs/GLOBAL-SPRINT-PLAN.md tracks the full sprint breakdown.
docs/COMING-SOON-AUDIT.md removed, folded into docs/KNOWN-ISSUES.md.
docs/BACKEND.md updated with the new documentationUrl bootstrap field.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 17:48:50 +04:00
|
|
|
reports: { title: string; description: string };
|
|
|
|
|
settings: { title: string; description: string };
|
feat(admin): Seller Management Phase 1 UI - Partners section, empty state, request/learn-more dialogs
No backend, no CRUD, no API, no business logic - production-quality
UI only, built entirely from existing shared components (app-dialog,
app-empty-state, app-button, app-form-field, app-input, app-icon,
app-badge). Gated per ADR-011: reads
modules.sellerManagement.enabled from bootstrap (always false today,
no backend sets it) rather than hardcoding disabled state.
New:
- AdminSellerManagementPageComponent (features/admin/seller-management/
pages/) - renders the specified empty state (title/description/
Request Access + Learn More buttons) using existing shared/ui
primitives only, no new UI infrastructure.
- Request Access dialog: Company/Email/Message form via
app-form-field + app-input + a plain textarea (no dedicated
textarea component exists yet, styled to match app-input's own
tokens exactly). Submission is mocked (setTimeout), no API call.
On submit: closes and opens a success dialog ("Thank you...").
- Learn More dialog: 6 capability bullets (seller dashboards,
storefronts, permissions, analytics, product ownership, marketplace
administration) under a "Coming Soon" badge.
- New admin nav group "Partners" > "Seller Management" link
(admin-nav.model.ts), new route /backoffice/partners/seller-management
(app.routes.ts), using the same loadComponent/breadcrumb pattern as
every other admin route.
Translations: full en/ru/hy coverage, zero hardcoded strings - new
adminShell.nav.{partnersGroup,sellerManagement},
adminShell.pages.sellerManagement, and a new adminSellerManagement.*
namespace (emptyState/requestDialog/requestSuccessDialog/
learnMoreDialog) added to translations.ts (types) and all three
locale files.
Accessibility: inherited from app-dialog (role="dialog",
aria-modal, focus trap on Tab/Shift+Tab, Escape to close, focus
restored to trigger on close) - no new a11y code needed, reused as-is.
Responsive: existing --space-*/--font-size-* tokens throughout,
flex-wrap on button row, mobile breakpoint stacks actions full-width.
Verified live (ru locale, devBypassAdmin): nav group/link render
correctly, breadcrumb shows "Управление продавцами", empty state
copy matches spec exactly, Request Access dialog opens with all 3
fields + Cancel/Send Request, filled + submitted -> success dialog
with exact spec copy, Learn More dialog shows all 6 bullets + Coming
Soon badge, no console errors, verified again at 375px mobile
viewport. tsc --noEmit clean, ng build clean (pre-existing bundle-
budget warning only), arch:check (boundaries + cycles) clean.
2026-07-26 20:47:18 +04:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
adminSellerManagement: {
|
|
|
|
|
emptyState: {
|
|
|
|
|
title: string;
|
|
|
|
|
description: string;
|
|
|
|
|
requestAccess: string;
|
|
|
|
|
learnMore: string;
|
|
|
|
|
};
|
|
|
|
|
requestDialog: {
|
|
|
|
|
title: string;
|
|
|
|
|
companyLabel: string;
|
|
|
|
|
companyPlaceholder: string;
|
|
|
|
|
emailLabel: string;
|
|
|
|
|
emailPlaceholder: string;
|
|
|
|
|
messageLabel: string;
|
|
|
|
|
messagePlaceholder: string;
|
|
|
|
|
cancel: string;
|
|
|
|
|
send: string;
|
|
|
|
|
};
|
|
|
|
|
requestSuccessDialog: {
|
|
|
|
|
title: string;
|
|
|
|
|
message: string;
|
|
|
|
|
close: string;
|
|
|
|
|
};
|
|
|
|
|
learnMoreDialog: {
|
|
|
|
|
title: string;
|
|
|
|
|
comingSoonBadge: string;
|
|
|
|
|
features: {
|
|
|
|
|
sellerDashboards: string;
|
|
|
|
|
sellerStorefronts: string;
|
|
|
|
|
sellerPermissions: string;
|
|
|
|
|
sellerAnalytics: string;
|
|
|
|
|
productOwnership: string;
|
|
|
|
|
marketplaceAdministration: string;
|
|
|
|
|
};
|
|
|
|
|
close: string;
|
feat(admin): build shared admin shell
Sidebar (Dashboard/Catalog group/Products/Categories/Orders/Transactions/
Reviews/Reports/Content/Media/Marketplace Builder/Users/Settings/
Monitoring/Analytics + Documentation/Help/Logout), sticky topbar
(breadcrumbs, page title/description, search, notifications, tenant
selector and quick-publish placeholders, current user), reserved
right-rail slot, scrollable content area. Desktop 280px sidebar, tablet
icon rail, mobile drawer with focus management and Escape-to-close.
Nav items without a built page (Reviews, Reports, Settings, Docs, Help)
render disabled with a coming-soon badge instead of dead links; Content
and Marketplace Builder route to the existing project-editor pages
(static-pages / general) rather than duplicating them.
All 15 /backoffice/** routes now render through AdminLayoutComponent;
the public storefront header/back-button/footer no longer render on
admin routes (app.ts/app.html gate on a new isAdminRoute signal).
Added the adminShell i18n namespace (ru/en/hy) for every new shell
string so this doesn't add to the existing untranslated-admin-UI gap
tracked in KNOWN-ISSUES.md.
Colors/type sizes follow DESIGN.md tokens; the two rgba() modal-scrim
values are a documented, intentional exception (neutral overlay,
not a themed token).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 00:12:19 +04:00
|
|
|
};
|
|
|
|
|
};
|
2026-02-26 23:09:20 +04:00
|
|
|
}
|