191 lines
3.4 KiB
Markdown
191 lines
3.4 KiB
Markdown
# Media Viewer Page
|
|
|
|
## Overview
|
|
|
|
**File Path:** `admin/src/pages/public/MediaViewerPage.tsx` (306 lines)
|
|
|
|
**Route:** `/media/:id`
|
|
|
|
**Role Requirements:** Public access (locked videos require login)
|
|
|
|
**Purpose:** Individual video player page with metadata, reactions, comments, and related videos.
|
|
|
|
**Key Features:**
|
|
|
|
- Back button to gallery
|
|
- VideoPlayer component with time tracking
|
|
- Metadata display (views, upvotes, category, quality tags)
|
|
- Upvote button (toggleable, session-based)
|
|
- ReactionButtons component (6 emojis)
|
|
- CommentSection component
|
|
- Related videos grid (3 cards)
|
|
- Locked video modal (redirect to login)
|
|
|
|
---
|
|
|
|
## Features
|
|
|
|
### 1. Video Player
|
|
|
|
```tsx
|
|
<VideoPlayer
|
|
videoUrl={video.videoUrl}
|
|
onTimeUpdate={(currentTime) => {
|
|
// Track view progress
|
|
if (currentTime > lastTrackedTime + 30) {
|
|
trackView(video.id, currentTime);
|
|
setLastTrackedTime(currentTime);
|
|
}
|
|
}}
|
|
/>
|
|
```
|
|
|
|
### 2. Metadata Display
|
|
|
|
```tsx
|
|
<Space size={16}>
|
|
<Text type="secondary">
|
|
<EyeOutlined /> {video.viewCount} views
|
|
</Text>
|
|
<Text type="secondary">
|
|
<LikeOutlined /> {video.upvotes} upvotes
|
|
</Text>
|
|
<Tag color="blue">{video.category}</Tag>
|
|
{video.quality && <Tag color="green">{video.quality}p</Tag>}
|
|
</Space>
|
|
```
|
|
|
|
### 3. Upvote Button
|
|
|
|
```tsx
|
|
<Button
|
|
type={hasUpvoted ? 'primary' : 'default'}
|
|
icon={hasUpvoted ? <LikeFilled /> : <LikeOutlined />}
|
|
onClick={handleUpvote}
|
|
size="large"
|
|
>
|
|
Upvote ({video.upvotes})
|
|
</Button>
|
|
```
|
|
|
|
### 4. Reaction Buttons
|
|
|
|
6 emoji reactions:
|
|
- 👍 Like
|
|
- ❤️ Love
|
|
- 😂 Haha
|
|
- 😮 Wow
|
|
- 😢 Sad
|
|
- 😡 Angry
|
|
|
|
```tsx
|
|
<ReactionButtons
|
|
videoId={video.id}
|
|
reactions={video.reactions}
|
|
onReact={handleReact}
|
|
/>
|
|
```
|
|
|
|
### 5. Comment Section
|
|
|
|
```tsx
|
|
<CommentSection
|
|
videoId={video.id}
|
|
comments={comments}
|
|
onSubmit={handleCommentSubmit}
|
|
/>
|
|
```
|
|
|
|
### 6. Related Videos
|
|
|
|
```tsx
|
|
<Title level={4}>Related Videos</Title>
|
|
<Row gutter={[16, 16]}>
|
|
{relatedVideos.slice(0, 3).map(video => (
|
|
<Col xs={24} sm={8} key={video.id}>
|
|
<PublicVideoCard video={video} />
|
|
</Col>
|
|
))}
|
|
</Row>
|
|
```
|
|
|
|
### 7. Locked Video Handling
|
|
|
|
```tsx
|
|
{video.isLocked && !user && (
|
|
<Modal
|
|
title="Login Required"
|
|
open={true}
|
|
footer={
|
|
<Button type="primary" onClick={() => navigate('/login')}>
|
|
Go to Login
|
|
</Button>
|
|
}
|
|
>
|
|
This video requires login to view.
|
|
</Modal>
|
|
)}
|
|
```
|
|
|
|
---
|
|
|
|
## API Integration
|
|
|
|
### Endpoints
|
|
|
|
#### 1. Get Video
|
|
```http
|
|
GET /api/media/public/:id
|
|
```
|
|
|
|
#### 2. Track View
|
|
```http
|
|
POST /api/media/public/:id/view
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"currentTime": 67.5
|
|
}
|
|
```
|
|
|
|
#### 3. Toggle Upvote
|
|
```http
|
|
POST /api/media/public/:id/upvote
|
|
```
|
|
|
|
#### 4. Add Reaction
|
|
```http
|
|
POST /api/media/public/:id/react
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"reactionType": "love"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Performance Considerations
|
|
|
|
1. **View Tracking**: Throttled to 30-second intervals
|
|
2. **Related Videos**: Limited to 3 (prevents over-fetching)
|
|
3. **Lazy Comments**: Loaded separately after video metadata
|
|
4. **Video Preload**: `preload="metadata"` for faster initial render
|
|
|
|
---
|
|
|
|
## Accessibility
|
|
|
|
- **Keyboard Controls**: Native video player controls
|
|
- **Captions**: Support for WebVTT subtitle files
|
|
- **Screen Reader**: All buttons have aria-labels
|
|
- **Focus Management**: Reaction buttons keyboard navigable
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- [Media Gallery Page](./media-gallery-page.md)
|
|
- [Video Upload](../../components/media/upload-video-modal.md)
|
|
- [Media API](../../../api/modules/media/routes.md)
|