# Dashboard UX Review: translate-press-zone

**Date:** 2026-03-15
**Reviewed by:** UX analysis of current implementation
**Source files:** `admin/src/pages/dashboard.js`, `admin/src/sections/analytics-dashboard.js`, `includes/class-tpz-rest-api.php` (get_stats)

---

## 1. What's Working Well

- **Clean visual hierarchy**: The 4 stat cards at the top provide an immediate overview. The card-based layout with consistent spacing looks professional inside the WordPress admin.
- **Live data**: Stats pull from real job data (`presszone_translate_jobs` table), not mocks. The numbers are meaningful.
- **Auto-refresh**: Jobs table refreshes every 30 seconds -- good for monitoring in-progress translations.
- **Error handling**: Both stats and jobs have loading skeletons, error states, and fallback rendering. The system status section shows API/cache/license health with color-coded badges.
- **Retry action on failed jobs**: The "Retry" button on failed jobs is contextually appropriate -- it only appears when relevant.
- **Empty state with CTA**: When there are no jobs, an "Create Translation" button is shown -- good onboarding.
- **Analytics integration**: Volume chart and top languages table are embedded directly in the dashboard rather than hidden on a separate page.

---

## 2. What's Missing or Could Be Improved

### 2a. Critical Missing Metrics

**Translation Coverage (the #1 question admins have)**
The dashboard shows "Active Translations: 79" and "Completion Rate: 67%" but these are job-level metrics (completed jobs / total jobs). They do NOT answer "how much of my content is translated?"

- **Missing**: Total posts count, translated posts count, per-language coverage
- **Current `completion_rate`**: Calculated as `completed_jobs / total_jobs * 100` -- this measures job success rate, not content coverage
- **What admins actually want**: "I have 150 posts, 95 are translated to Hebrew, 42 to Spanish" -- a per-language breakdown

**Recommendation**: Replace or supplement "Completion Rate" with a **Content Coverage** metric that shows posts translated vs. total posts, broken down per language. The data already exists -- `get_posts_translation_status()` in MPZAdapter returns per-post translation status.

**Credit/Budget Awareness**
- Credits are hardcoded to 500000 for "professional" plan (`$credits = 500000; // Mock based on plan for now`)
- No credit balance is shown on the dashboard
- No usage-vs-quota visualization
- Admins cannot answer: "Am I running low on credits?"

**Recommendation**: Add a "Credits Remaining" stat card (or replace "Characters Used" with a usage gauge showing used/available). The backend API at `api.press.zone` likely has a credits endpoint -- or the license response should include remaining balance.

**Failed/Stuck Translations Alert**
- Failed jobs are visible in the jobs table but there is no top-level count or alert
- An admin scanning the dashboard quickly might miss a failure buried in row 7 of the table
- The `handleRetryJob()` method is a stub (the API call is commented out)

**Recommendation**: Add a "Needs Attention" stat card or alert banner at the top showing count of failed/stuck jobs. Make the retry action functional.

### 2b. Stat Cards Are Misleading

| Current Card | What It Shows | What Admins Think It Means |
|---|---|---|
| Active Translations (79) | Completed jobs count | Number of posts that are actively translated |
| Total Languages (2) | `get_active_languages()` count | All configured languages (should be 3: en, he, es) |
| Completion Rate (67%) | Jobs completed / total jobs | Percentage of content translated |
| Characters Used (106,424) | Total chars across completed jobs | How much of my budget I've used |

**Problems**:
1. "Active Translations" label suggests ongoing work, but it shows completed count
2. "Total Languages" uses `get_active_languages()` (2) instead of `get_all_configured_languages()` (3) -- inconsistent with the rest of the plugin which includes inactive languages
3. "Completion Rate" is a job success metric, not a coverage metric
4. "Characters Used" is a raw number with no context -- is 106K a lot? Out of what total?

### 2c. Information Overload at the Bottom

The bottom section has three cards side by side:
- Recent Translation Jobs (large table, 10 rows)
- Quick Actions (3 buttons)
- System Status (3 items)

**Issues**:
- The jobs table dominates but shows ALL jobs regardless of status, making it hard to spot problems
- Quick Actions are low-value for repeat users (you don't add a language every day)
- System Status is always green unless something is broken -- it's noise 95% of the time

**Recommendation**:
- Add a status filter or tab to the jobs table (Failed | In Progress | All)
- Move Quick Actions to the header area or collapse into a dropdown
- Make System Status a compact inline banner at the top that only draws attention when something is wrong (pattern: green checkmark when all OK, red alert when not)

### 2d. The Analytics Section Feels Disconnected

The "Analytics" header with "Refresh" button creates a visual break between stats cards and the charts. It feels like two separate pages stitched together.

**Recommendation**: Remove the "Analytics" sub-header. Let the charts flow naturally below the stat cards as part of one continuous dashboard narrative: overview -> trends -> details.

### 2e. Top Languages Table Redundancy

The "Top Languages" table shows Language Pair, Completed Jobs, and Characters. This partially duplicates information from the stat cards and the jobs table.

**Recommendation**: Add an "Avg Characters/Job" column (already in the table headers in the baseline screenshot but removed in current version) and a visual bar showing relative volume. This makes the table useful for understanding translation patterns rather than just restating numbers.

---

## 3. Information Hierarchy Issues

### Current hierarchy (top to bottom):
1. Header (Dashboard title)
2. Stats cards (aggregate numbers)
3. Analytics sub-header
4. Translation Volume chart
5. Top Languages table
6. Recent Jobs table
7. Quick Actions
8. System Status

### Recommended hierarchy:
1. **Alert banner** (only if: failed jobs > 0, license expiring, API down) -- draw attention to problems first
2. **Content Coverage cards** (posts translated per language, overall coverage %) -- answer the #1 question
3. **Usage & Budget** (characters used / quota, with visual gauge) -- answer the #2 question
4. **Recent Activity** (jobs table, filtered to show problems first, then recent) -- answer "what happened recently?"
5. **Trends** (volume chart, collapsed or smaller) -- secondary information
6. **System Status** (inline, compact, only prominent when broken)

### Key principle:
The current dashboard is organized around **what the system does** (jobs, languages, characters). It should be organized around **what the admin needs to know** (coverage, budget, problems, progress).

---

## 4. More Useful Metrics for WordPress Admins

### Replace or add these metrics:

| Metric | Why It Matters | Data Source |
|---|---|---|
| **Untranslated Posts** (count) | "What's left to do?" | `get_posts_translation_status()` -- count posts missing any target language |
| **Per-Language Coverage** (%) | "How complete is each language?" | Posts with translation / total posts, per language |
| **Credits Remaining** | "Am I going to run out?" | License/billing API or stored quota |
| **Failed Jobs** (count) | "Do I need to fix anything?" | `WHERE status = 'failed'` count from jobs table |
| **Characters This Month** | "What's my current burn rate?" | Jobs table filtered to current month |
| **Last Translation** (timestamp) | "Is the system working?" | Most recent completed job timestamp |
| **Estimated Cost** | "What will this cost me?" | Already existed in baseline screenshot ("Estimated Costs" chart) but was removed |

### Metrics to demote or remove:

| Current Metric | Issue |
|---|---|
| **Active Translations (79)** | Misleading label, not actionable |
| **Total Languages (2)** | Static number, rarely changes, wastes prime dashboard space |
| **Completion Rate (67%)** | Measures job success, not content coverage |

---

## 5. Quick Wins (Implementable Immediately)

### Win 1: Fix stat card labels and data (30 min)
- Rename "Active Translations" to "Completed Jobs" or "Translated Posts"
- Rename "Completion Rate" to "Job Success Rate" (or better: calculate real content coverage)
- Change `total_languages` in `get_stats()` to use `get_all_configured_languages()` instead of `get_active_languages()` to match the rest of the plugin
- Add context to "Characters Used": show as "106,424 / 500,000" if quota is known

### Win 2: Add failed jobs count to stats (15 min)
In `get_stats()`, add:
```php
$failed_jobs = (int) $wpdb->get_var(
    "SELECT COUNT(*) FROM {$jobs_table} WHERE status = 'failed'"
);
```
Display as a stat card with `variant: 'error'` when > 0, or add a warning banner at the top.

### Win 3: Make retry button functional (15 min)
The `handleRetryJob()` method has the API call commented out. Uncomment and connect it:
```js
await api.post(`/jobs/${jobId}/retry`);
```

### Win 4: Add "Untranslated Posts" stat card (30 min)
Query total publishable posts minus posts that have translations for ALL configured languages. This directly answers "what's left to translate?" -- the most common reason to visit the dashboard.

### Win 5: Collapse System Status when healthy (15 min)
When all three status items are "active", render as a single-line "All systems operational" with a green dot. Only expand to full card when something is wrong. This reduces visual noise significantly.

### Win 6: Sort jobs table to show problems first (10 min)
In `loadRecentJobs()`, after fetching, sort the array so failed/processing jobs appear before completed ones:
```js
this.recentJobs.sort((a, b) => {
    const priority = { failed: 0, processing: 1, running: 1, queued: 2, completed: 3 };
    return (priority[a.status] ?? 3) - (priority[b.status] ?? 3);
});
```

### Win 7: Add "last updated" timestamp (5 min)
Show when the dashboard data was last fetched. This builds trust and helps debug stale data issues. Add a small timestamp below the stats grid or in the header.

---

## Summary

The dashboard is visually polished but functionally misaligned with what WordPress admins need. The core problem: it reports on **system activity** (jobs, characters, languages) when admins need **content status** (coverage, gaps, problems, budget). The stat cards use misleading labels that make admins think they're seeing content coverage when they're seeing job metrics.

**Priority order for improvements:**
1. Fix misleading stat labels (immediate credibility fix)
2. Add content coverage metric (answers the #1 user question)
3. Add failed jobs alert (prevents silent failures)
4. Add credit/budget visibility (prevents surprise overages)
5. Reorganize information hierarchy (coverage > problems > activity > trends)
