New line chart shows accumulated sell-out (€) or units month by month,
comparing all available years on the same axis for like-for-like
year-over-year tracking.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Filter sales records with year > 2023 and skip ads Excel sheets
for year <= 2023. Bump schema version to 4 to invalidate cached
2023 records in IndexedDB.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Pass ytdFilteredAdsData instead of filteredAdsData so previous years
are capped at the same max week as the current year, enabling
like-for-like YoY advertising comparisons.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Previously the Filtered Totals header row summed ad spend from pivot rows,
which excluded ads-only records (ASINs with zero sales) due to isRealSale filter.
Now uses adSpendByYear memo from raw adsData, matching Dashboard calculation.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Shows previous week and same week prior year values (Units, Revenue, Ads Spend, GV) with % change indicators when hovering any week cell in the TOTALS row.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Added stockMap, vendorStockMap, buyBoxLostMap, top50Mode to Dashboard props destructuring
- This fixes 'stockMap is not defined' error in TopMovers
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Add || null to years array access to prevent undefined values
- Add !currentYear || !previousYear to insufficient data check
- This prevents errors when filtered data has less than 2 years
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Removed debug console.log that was accessing data before null check
- Fixed colSpan in TopMovers empty state message (7 -> 10 columns)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Added StockBadge, VendorStockBadge and BuyBoxWarningBadge to TopMovers component
- Updated Dashboard to pass stockMap, vendorStockMap, buyBoxLostMap and top50Mode props
- Updated App.tsx to pass the required maps to Dashboard
- Table now shows 3 new columns: Stock (GMBH), Vendor (Amazon Warehouse), and Buy Box status
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Changed rawData prop from rawData to ytdFilteredData so the Top Movers
component respects all active filters (customer, year, month, week,
product line, SKU, title, ASIN, stock)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Move useMemo before early return in WaterfallModal to comply with Rules of Hooks.
Wrap App with ErrorBoundary so future render crashes show an error panel instead of a silent black screen.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
filteredAdsData applies PAN_EU default when no marketplace is selected,
cutting UK/other spend and showing 118k instead of the full 151k.
mktAdsData skips the PAN_EU restriction: no customer filter = all
countries, still respects explicit customer/year/week selections.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removed the `if (asin)` guard so records without a product ASIN
(e.g. campaign-level rows) accumulate in adsSpendMap and appear as
an 'Unassigned Ad Spend' row, ensuring the total PPC spend is the
same as in the ADs Weekly tab.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These Excel files only contain 2025 data. When the top filter excludes
2025 (e.g. year=2024), the maps are ignored so columns show 0 instead
of stale 2025 figures.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs fixed:
1. Removed hardcoded year===2025 filter (data is already pre-filtered)
2. ASINs with ad spend but no sales records were silently dropped —
now appended as extra rows so the total PPC spend matches ADs Weekly
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MktDataView now receives filteredData/filteredAdsData so the global
FilterBar controls the tab's data. Removed the local "All Categories"
dropdown that previously sat next to the Include COGS toggle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace fetch-deals, fetch-promos, fetch-chargebacks with a single
/api/fetch-mkt-data?file=deals|promos|chargebacks endpoint.
Update MktDataView fetch calls accordingly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all mock data in the Profitability Dashboard with live data:
- Add 3 new API routes (fetch-deals, fetch-promos, fetch-chargebacks) proxying Dropbox Excel files
- MktDataView now accepts rawData/adsData props and fetches+parses the 3 new files on mount
- SELL OUT and units aggregated globally across all marketplaces from rawData
- PPC Spend aggregated globally from adsData; ACoS calculated as spend/sales
- Deals (col A→C), Promos (col E→K), Chargebacks (col AN→B) parsed and summed per ASIN
- Category filter populated from product line metadata
- Loading skeleton shown while files are fetching
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BSRRecord.market is stored as short codes ('DE', 'IT', etc.) from the
Excel file, but the chart was comparing against full names ('Amazon DE',
'Amazon IT', etc.) — causing bsrRecordsForMarket to always be empty and
the BSR line to never render. Added normalizeBsrMarket() to map short
codes to full names before filtering. Also removed the debug strip.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use React's useDeferredValue to decouple UI responsiveness from
expensive data reprocessing. Checkboxes now update immediately on
click; filterData/filterAdsData/filterBsrData and all downstream
useMemos run as a low-priority background pass. Added local optimistic
state in MultiSelectDropdown as a belt-and-suspenders layer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- winner if posterior probability > 50%, unsuccessful otherwise
- Removes inconclusive — binary outcome based on Bayesian signal
- Label "Loser" renamed to "Unsuccessful"
- Updated all stored experiment verdicts in DB
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Split by comma/semicolon/newline first; only split by spaces for
non-LINE: tokens so "LINE:MAGIC DOUGH" isn't broken into two parts.
Also fix placeholder and repair stored experiment data via API.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Detail category BSR is more granular and relevant per ASIN. Falls back
to topLevelBSR if detailLevelBSR is null for a record.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Math.max(...largeArray) crashes when combinedAdsData has thousands of
records. Replaced with a simple for-loop to find the max year safely.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New BSRUnitsCorrelationChart component added to the Vendor tab showing:
- Per-marketplace tabs (DE, ES, FR, IT, UK) with market accent colors
- Dual-axis combo chart: bars (units sold, right axis) + line (BSR rank, left axis)
- Inverted BSR axis by default (lower rank = top) with toggle to flip
- Pearson r correlation calculated and displayed with strength interpretation
- Wired to existing combinedAdsData (filtered) and filteredBsrData
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The badge was rendered outside the stockMap conditional, causing it to
appear independently of the Amazon stock badge. Now it's grouped inside
the block, always appearing immediately next to VendorStockBadge.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Wrap component with memo() to prevent unnecessary re-renders
- Restructure DOM hierarchy to avoid nested inline-flex containers
- Center hover popup with left-1/2 -translate-x-1/2
- Add pointer-events-none to popup to prevent hover flickering
- Improve popup spacing and sizing
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
The BuyBoxWarningBadge was appearing twice - once next to the SKU and once next to Amazon stock. Now it only appears next to Amazon stock as requested.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Each market line (DE/ES/FR/IT/UK) now renders with its own color across
Top Level BSR, Detail Level BSR, and Average Rating charts, along with
per-market legend entries. Removes hardcoded single-color approach.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add translateCategory() with a full DE/FR/IT/ES → EN map covering
all top-level and detail categories found in the BSR data.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use BarChart with rounded corners for modern look
- Remove vertical grid lines for cleaner appearance
- Add hover cursor effect on tooltip
- Y-axis reversed for BSR charts (lower = better)
- Normal Y-axis for Rating chart (higher = better)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Replace bar charts with area charts featuring:
- Gradient fill effects for modern look
- Smooth monotone curves
- Proper Y-axis orientation (reversed for BSR where lower is better)
- Color-coded by market with transparency
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Convert Top Level BSR, Detail Level BSR, and Average Rating charts
from LineChart to BarChart for better week-over-week comparison.
Each market now displays as colored bars per week instead of lines.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
FR/UK/DE sheets have a 'Status' column that appears before 'Reason',
causing the dynamic detector to pick the wrong column.
Use confirmed indices: FR=col S(18), UK=col J(9), DE=col N(13).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Inventory sheets like 'INV ITALY' were being incorrectly matched as
buybox sheets, adding all their ASINs as false BB lost entries.
Now only sheets starting with 'BB' are processed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace fragile header/column-index approach with pattern-based ASIN detection:
- Scan all cells for Amazon ASIN pattern (B[0-9A-Z]{9}) to auto-detect the ASIN column regardless of headers or position
- Detect country from sheet name with flexible matching (no hardcoded sheet name list)
- Detect reason column from header keywords, no hardcoded column indices
- Remove all hardcoded fallback indices (col 13, 18, 9, etc.) that caused empty results
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>