Import remaining project documentation and reference notes
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
# Phase 11 Track 1 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Close 5 functional gaps in the Teknav Admin Panel where backend support is already present but UI wiring is missing.
|
||||
|
||||
**Architecture:** Modify existing React components in `teknav-admin.jsx` to add form fields, filters, dedicated tabs, and bulk operation controls.
|
||||
|
||||
**Tech Stack:** React 18, Fastify (Backend), Prisma, custom CSS-in-JS (via `teknav-ui.jsx`).
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Article Editor Flags Toggles
|
||||
|
||||
**Files:**
|
||||
- Modify: `teknav-admin.jsx`
|
||||
|
||||
- [ ] **Step 1: Locate flags group in ArticleEditor**
|
||||
Find the "نشانهگذاری" group in the `ArticleEditor` component (approx line 1500-1600).
|
||||
|
||||
- [ ] **Step 2: Add toggles for premiumOnly, sponsored, and featured**
|
||||
Update the array of flags to include all three fields. Ensure `premiumOnly` uses a lock icon, `sponsored` uses a star/badge, and `featured` uses a star.
|
||||
|
||||
```javascript
|
||||
// Inside ArticleEditor flags group
|
||||
{[
|
||||
{ key: 'premiumOnly', label: 'فقط اعضای ویژه', icon: '🔒' },
|
||||
{ key: 'sponsored', label: 'محتوای حمایتشده', icon: '⭐' },
|
||||
{ key: 'featured', label: 'مقاله ویژه', icon: '★' },
|
||||
].map(({ key, label, icon }) => (
|
||||
<div key={key} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: '#263238', cursor: 'pointer' }}>
|
||||
<span style={{ fontSize: 14 }}>{icon}</span>
|
||||
<span>{label}</span>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => set(key, !form[key])}
|
||||
style={{
|
||||
width: 44, height: 24, borderRadius: 12, border: 'none', cursor: 'pointer',
|
||||
background: form[key] ? BRAND.primary : '#D0CCC5',
|
||||
position: 'relative', transition: 'background 0.2s', flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<span style={{
|
||||
position: 'absolute', top: 3, width: 18, height: 18, borderRadius: '50%', background: '#fff',
|
||||
transition: 'inset-inline-start 0.2s',
|
||||
insetInlineStart: form[key] ? 23 : 3,
|
||||
}} />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify form state update**
|
||||
Ensure `handleSave` correctly includes these new boolean fields in the `data` object sent to `adminApi.createArticle` or `adminApi.updateArticle`.
|
||||
|
||||
- [ ] **Step 4: Manual verification**
|
||||
Open a "Published" article in the editor, toggle "Premium Only", save, and verify it persists (check local browser network tab).
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Content Freshness Filter
|
||||
|
||||
**Files:**
|
||||
- Modify: `teknav-admin.jsx`
|
||||
|
||||
- [ ] **Step 1: Locate filter bar in ArticlesManagement**
|
||||
Find the `ArticlesManagement` component and its filter inputs (approx line 300-400).
|
||||
|
||||
- [ ] **Step 2: Add freshness filter dropdown**
|
||||
Add a new `<select>` for `freshnessFilter` with options: همه | بهروز | نیاز به بازنگری | قدیمی.
|
||||
|
||||
```javascript
|
||||
<select value={freshnessFilter} onChange={e => setFreshnessFilter(e.target.value)} style={{ ...inputStyle, maxWidth: 180 }} dir="rtl">
|
||||
<option value="">همه تازگیها</option>
|
||||
<option value="up_to_date">بهروز</option>
|
||||
<option value="needs_update">نیاز به بازنگری</option>
|
||||
<option value="outdated">قدیمی</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Update filtering logic**
|
||||
Ensure `filtered` useMemo includes the freshness filter logic:
|
||||
|
||||
```javascript
|
||||
if (freshnessFilter) list = list.filter(a => a.contentFreshnessStatus === freshnessFilter);
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Manual verification**
|
||||
Change the dropdown value and ensure the table updates to show only articles with the matching status.
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Dedicated SEO Audit Tab
|
||||
|
||||
**Files:**
|
||||
- Modify: `teknav-admin.jsx`
|
||||
|
||||
- [ ] **Step 1: Register new tab in SIDEBAR_ITEMS**
|
||||
Add `{ id: 'seo-audit', label: 'ممیزی SEO', icon: '◈' }` to the `admin` role in `SIDEBAR_ITEMS`.
|
||||
|
||||
- [ ] **Step 2: Update AdminPanel to handle 'seo-audit' tab**
|
||||
In the main `AdminPanel` render loop, add a case for `activeTab === 'seo-audit'`.
|
||||
|
||||
- [ ] **Step 3: Move SeoAuditPanel rendering**
|
||||
Ensure `SeoAuditPanel` is rendered as the primary component for the new tab.
|
||||
|
||||
- [ ] **Step 4: Manual verification**
|
||||
Click the "SEO Audit" item in the sidebar and verify it renders the full audit table.
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Engagement Analytics Enhancements
|
||||
|
||||
**Files:**
|
||||
- Modify: `teknav-admin.jsx`
|
||||
|
||||
- [ ] **Step 1: Expand EngagementAnalyticsPanel**
|
||||
Enhance the existing `EngagementAnalyticsPanel` to show more detail.
|
||||
|
||||
- [ ] **Step 2: Add 7-day event count chart**
|
||||
Re-use `WeeklyChart` or the area-SVG pattern to visualize `engagement.weeklyData`.
|
||||
|
||||
- [ ] **Step 3: Add Top 5 articles table**
|
||||
Render `engagement.topArticles` in a simple list or table.
|
||||
|
||||
- [ ] **Step 4: Manual verification**
|
||||
Open Analytics -> Engagement tab and verify charts and tables populate with real data.
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Bulk Comment Moderation UI
|
||||
|
||||
**Files:**
|
||||
- Modify: `teknav-admin.jsx`
|
||||
|
||||
- [ ] **Step 1: Add selection state to CommentsModeration**
|
||||
Ensure `selected` Set state is active (it seems partially present in the current code section).
|
||||
|
||||
- [ ] **Step 2: Add floating action bar**
|
||||
Render the bulk action bar at the bottom of the screen when `selected.size > 0`.
|
||||
|
||||
```javascript
|
||||
{selected.size > 0 && (
|
||||
<div style={{ position: 'fixed', bottom: 24, left: '50%', transform: 'translateX(-50%)', background: BRAND.ink, color: '#fff', borderRadius: 14, padding: '12px 20px', display: 'flex', alignItems: 'center', gap: 12, zIndex: 600 }}>
|
||||
<span style={{ fontWeight: 700 }}>{selected.size.toLocaleString('fa-IR')} مورد انتخاب شده</span>
|
||||
<button onClick={() => bulkAction('delete')} style={bulkBtnStyle}>حذف</button>
|
||||
<button onClick={() => bulkAction('approve')} style={bulkBtnStyle}>تأیید</button>
|
||||
<button onClick={() => setSelected(new Set())}>لغو</button>
|
||||
</div>
|
||||
)}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Wire bulkAction to API**
|
||||
Call `adminApi.bulkModerateComments(ids, action)` and refresh the list.
|
||||
|
||||
- [ ] **Step 4: Manual verification**
|
||||
Check 2-3 comments, click "Approve", and verify they are processed and the selection is cleared.
|
||||
Reference in New Issue
Block a user