Series to Collection Function
This commit is contained in:
@@ -4,7 +4,7 @@ import { useState, useEffect } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
import { storyApi, seriesApi, audioCoveApi, getImageUrl } from '../../../../lib/api';
|
||||
import { storyApi, seriesApi, audioCoveApi, collectionApi, getImageUrl } from '../../../../lib/api';
|
||||
import { Story, Collection } from '../../../../types/api';
|
||||
import AppLayout from '../../../../components/layout/AppLayout';
|
||||
import Button from '../../../../components/ui/Button';
|
||||
@@ -26,6 +26,7 @@ export default function StoryDetailPage() {
|
||||
const [isExporting, setIsExporting] = useState(false);
|
||||
const [isSendingToAudioCove, setIsSendingToAudioCove] = useState(false);
|
||||
const [audioCovedSuccess, setAudioCovedSuccess] = useState(false);
|
||||
const [isCreatingCollection, setIsCreatingCollection] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const loadStoryData = async () => {
|
||||
@@ -133,6 +134,20 @@ export default function StoryDetailPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateCollectionFromSeries = async () => {
|
||||
if (!story?.seriesId || isCreatingCollection) return;
|
||||
setIsCreatingCollection(true);
|
||||
try {
|
||||
const result = await seriesApi.createCollectionFromSeries(story.seriesId);
|
||||
router.push(`/collections/${result.collectionId}`);
|
||||
} catch (error: any) {
|
||||
const message = error?.response?.data || 'Failed to create collection from series.';
|
||||
alert(message);
|
||||
} finally {
|
||||
setIsCreatingCollection(false);
|
||||
}
|
||||
};
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
return new Date(dateString).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
@@ -319,6 +334,16 @@ export default function StoryDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-4">
|
||||
<Button
|
||||
onClick={handleCreateCollectionFromSeries}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
disabled={isCreatingCollection}
|
||||
>
|
||||
{isCreatingCollection ? 'Creating...' : '📚 Create Collection from Series'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Collection } from '../../types/api';
|
||||
import { collectionApi, getImageUrl } from '../../lib/api';
|
||||
import { collectionApi, audioCoveApi, getImageUrl } from '../../lib/api';
|
||||
import Button from '../ui/Button';
|
||||
import StoryReorderList from './StoryReorderList';
|
||||
import AddToCollectionModal from './AddToCollectionModal';
|
||||
@@ -29,6 +29,8 @@ export default function CollectionDetailView({
|
||||
const [editRating, setEditRating] = useState(collection.rating || '');
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [actionLoading, setActionLoading] = useState<string | null>(null);
|
||||
const [isSendingToAudioCove, setIsSendingToAudioCove] = useState(false);
|
||||
const [audioCoveSuccess, setAudioCoveSuccess] = useState(false);
|
||||
|
||||
const formatReadingTime = (minutes: number): string => {
|
||||
if (minutes < 60) {
|
||||
@@ -118,6 +120,21 @@ export default function CollectionDetailView({
|
||||
}
|
||||
};
|
||||
|
||||
const handleSendToAudioCove = async () => {
|
||||
if (isSendingToAudioCove) return;
|
||||
setIsSendingToAudioCove(true);
|
||||
try {
|
||||
await audioCoveApi.sendCollectionToAudioCove(collection.id);
|
||||
setAudioCoveSuccess(true);
|
||||
setTimeout(() => setAudioCoveSuccess(false), 3000);
|
||||
} catch (error: any) {
|
||||
const message = error?.response?.data || 'Failed to send to AudioCove. Please try again.';
|
||||
alert(message);
|
||||
} finally {
|
||||
setIsSendingToAudioCove(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
{/* Header Section */}
|
||||
@@ -305,6 +322,14 @@ export default function CollectionDetailView({
|
||||
>
|
||||
{actionLoading === 'delete' ? <LoadingSpinner size="sm" /> : 'Delete'}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={handleSendToAudioCove}
|
||||
disabled={isSendingToAudioCove || audioCoveSuccess || collection.storyCount === 0}
|
||||
className="flex-shrink-0"
|
||||
>
|
||||
{isSendingToAudioCove ? '🎧 Sending...' : audioCoveSuccess ? '✅ Sent!' : '🎧 Send to Audiocove'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Tags */}
|
||||
|
||||
@@ -619,6 +619,11 @@ export const seriesApi = {
|
||||
const response = await api.get(`/stories/series/${id}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
createCollectionFromSeries: async (seriesId: string): Promise<{ collectionId: string; name: string }> => {
|
||||
const response = await api.post(`/series/${seriesId}/create-collection`);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
// Search endpoints
|
||||
@@ -1169,6 +1174,11 @@ export const audioCoveApi = {
|
||||
const response = await api.post(`/stories/${storyId}/send-to-audiocove`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
sendCollectionToAudioCove: async (collectionId: string): Promise<string> => {
|
||||
const response = await api.post(`/collections/${collectionId}/send-to-audiocove`);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
// Image utility - now library-aware
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user