admin
Some checks are pending
Deploy Admin Panel / Deploy Admin Panel (push) Waiting to run
Deploy Admin Panel / Admin Panel Verification (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
Some checks are pending
Deploy Admin Panel / Deploy Admin Panel (push) Waiting to run
Deploy Admin Panel / Admin Panel Verification (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
This commit is contained in:
parent
b86e840cc6
commit
0cfd5f4524
3 changed files with 98 additions and 55 deletions
|
|
@ -52,8 +52,20 @@ export function BulkCardEditor({ images, onComplete, onCancel }: BulkCardEditorP
|
||||||
packsApi
|
packsApi
|
||||||
.getPacks({ page: 1, limit: 100, search: '' })
|
.getPacks({ page: 1, limit: 100, search: '' })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response && response.items) {
|
try {
|
||||||
setPacksData(response.items.map((pack) => ({ id: pack.id, title: pack.title })))
|
if (response && response.items && Array.isArray(response.items)) {
|
||||||
|
const packs = response.items.map((pack: any) => ({
|
||||||
|
id: String(pack.id || ''),
|
||||||
|
title: String(pack.title || pack.id || '')
|
||||||
|
}))
|
||||||
|
setPacksData(packs)
|
||||||
|
} else {
|
||||||
|
console.warn('Unexpected packs response format:', response)
|
||||||
|
setPacksData([])
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error processing packs response:', error)
|
||||||
|
setPacksData([])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|
@ -66,44 +78,48 @@ export function BulkCardEditor({ images, onComplete, onCancel }: BulkCardEditorP
|
||||||
|
|
||||||
// Initialize cards data
|
// Initialize cards data
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initialData = new Map<string, CardData>()
|
if (images.length > 0) {
|
||||||
images.forEach((image) => {
|
const initialData = new Map<string, CardData>()
|
||||||
initialData.set(image.id, {
|
images.forEach((image) => {
|
||||||
imageId: image.id,
|
initialData.set(image.id, {
|
||||||
packId: '',
|
imageId: image.id,
|
||||||
original: '',
|
packId: '',
|
||||||
translation: '',
|
original: '',
|
||||||
mnemo: '',
|
translation: '',
|
||||||
transcription: '',
|
mnemo: '',
|
||||||
transcriptionMnemo: '',
|
transcription: '',
|
||||||
back: '',
|
transcriptionMnemo: '',
|
||||||
imageBack: undefined,
|
back: '',
|
||||||
isSaved: false,
|
imageBack: undefined,
|
||||||
|
isSaved: false,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
setCardsData(initialData)
|
||||||
setCardsData(initialData)
|
}
|
||||||
}, [images])
|
}, [images])
|
||||||
|
|
||||||
const currentImage = images[currentIndex]
|
const currentImage = images[currentIndex]
|
||||||
const currentCard = cardsData.get(currentImage?.id || '')
|
const currentCard = currentImage ? cardsData.get(currentImage.id) : undefined
|
||||||
|
|
||||||
const updateMutation = useMutation({
|
const updateMutation = useMutation({
|
||||||
mutationFn: (card: GameCardDto) => cardsApi.upsertCard(card),
|
mutationFn: (card: GameCardDto) => cardsApi.upsertCard(card),
|
||||||
onSuccess: (response) => {
|
onSuccess: (response) => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['cards'] })
|
queryClient.invalidateQueries({ queryKey: ['cards'] })
|
||||||
const imageId = currentImage.id
|
if (currentImage) {
|
||||||
setCardsData((prev) => {
|
const imageId = currentImage.id
|
||||||
const newData = new Map(prev)
|
setCardsData((prev) => {
|
||||||
const cardData = newData.get(imageId)
|
const newData = new Map(prev)
|
||||||
if (cardData && response.card) {
|
const cardData = newData.get(imageId)
|
||||||
newData.set(imageId, {
|
if (cardData && response.card) {
|
||||||
...cardData,
|
newData.set(imageId, {
|
||||||
isSaved: true,
|
...cardData,
|
||||||
cardId: response.card.id,
|
isSaved: true,
|
||||||
})
|
cardId: response.card.id,
|
||||||
}
|
})
|
||||||
return newData
|
}
|
||||||
})
|
return newData
|
||||||
|
})
|
||||||
|
}
|
||||||
toast.success('Card saved successfully')
|
toast.success('Card saved successfully')
|
||||||
},
|
},
|
||||||
onError: (error: unknown) => {
|
onError: (error: unknown) => {
|
||||||
|
|
@ -113,7 +129,7 @@ export function BulkCardEditor({ images, onComplete, onCancel }: BulkCardEditorP
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleFieldChange = (field: keyof CardData, value: string) => {
|
const handleFieldChange = (field: keyof CardData, value: string) => {
|
||||||
if (!currentCard) return
|
if (!currentCard || !currentImage) return
|
||||||
|
|
||||||
setCardsData((prev) => {
|
setCardsData((prev) => {
|
||||||
const newData = new Map(prev)
|
const newData = new Map(prev)
|
||||||
|
|
@ -170,8 +186,21 @@ export function BulkCardEditor({ images, onComplete, onCancel }: BulkCardEditorP
|
||||||
const savedCount = Array.from(cardsData.values()).filter((card) => card.isSaved).length
|
const savedCount = Array.from(cardsData.values()).filter((card) => card.isSaved).length
|
||||||
const totalCount = images.length
|
const totalCount = images.length
|
||||||
|
|
||||||
|
// Wait for images and cards data to be initialized
|
||||||
|
if (images.length === 0) {
|
||||||
|
return (
|
||||||
|
<div className="p-4">
|
||||||
|
<p className="text-muted-foreground">No images uploaded</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (!currentImage || !currentCard) {
|
if (!currentImage || !currentCard) {
|
||||||
return <div>Loading...</div>
|
return (
|
||||||
|
<div className="p-4">
|
||||||
|
<p className="text-muted-foreground">Initializing card data...</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -199,15 +228,25 @@ export function BulkCardEditor({ images, onComplete, onCancel }: BulkCardEditorP
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Image Preview</CardTitle>
|
<CardTitle>Image Preview</CardTitle>
|
||||||
<CardDescription>{currentImage.file.name}</CardDescription>
|
<CardDescription>{currentImage.file?.name || 'Unknown'}</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="relative aspect-square border rounded-lg overflow-hidden bg-muted">
|
<div className="relative aspect-square border rounded-lg overflow-hidden bg-muted">
|
||||||
<img
|
{currentImage.preview ? (
|
||||||
src={currentImage.preview}
|
<img
|
||||||
alt={currentImage.file.name}
|
src={currentImage.preview}
|
||||||
className="w-full h-full object-contain"
|
alt={currentImage.file?.name || 'Card image'}
|
||||||
/>
|
className="w-full h-full object-contain"
|
||||||
|
onError={(e) => {
|
||||||
|
console.error('Failed to load image:', currentImage.preview)
|
||||||
|
e.currentTarget.style.display = 'none'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="w-full h-full flex items-center justify-center text-muted-foreground">
|
||||||
|
Image preview not available
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -222,19 +261,21 @@ export function BulkCardEditor({ images, onComplete, onCancel }: BulkCardEditorP
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="packId">Pack ID (optional)</Label>
|
<Label htmlFor="packId">Pack ID (optional)</Label>
|
||||||
<Select
|
<Select
|
||||||
value={currentCard.packId}
|
value={currentCard.packId || undefined}
|
||||||
onValueChange={(value: string) => handleFieldChange('packId', value)}
|
onValueChange={(value: string) => handleFieldChange('packId', value || '')}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Select a pack (optional)" />
|
<SelectValue placeholder="Select a pack (optional)" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="">None</SelectItem>
|
<SelectItem value="">None</SelectItem>
|
||||||
{packsData.map((pack) => (
|
{packsData && packsData.length > 0 ? (
|
||||||
<SelectItem key={pack.id} value={pack.id}>
|
packsData.map((pack) => (
|
||||||
{pack.title}
|
<SelectItem key={pack.id} value={pack.id}>
|
||||||
</SelectItem>
|
{pack.title || pack.id}
|
||||||
))}
|
</SelectItem>
|
||||||
|
))
|
||||||
|
) : null}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -366,19 +366,21 @@ export default function CardsPage() {
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="packId">Pack ID (optional)</Label>
|
<Label htmlFor="packId">Pack ID (optional)</Label>
|
||||||
<Select
|
<Select
|
||||||
value={formData.packId}
|
value={formData.packId || undefined}
|
||||||
onValueChange={(value: string) => setFormData(prev => ({ ...prev, packId: value }))}
|
onValueChange={(value: string) => setFormData(prev => ({ ...prev, packId: value || '' }))}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Select a pack (optional)" />
|
<SelectValue placeholder="Select a pack (optional)" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="">None</SelectItem>
|
<SelectItem value="">None</SelectItem>
|
||||||
{packsData?.items.map((pack) => (
|
{packsData?.items && packsData.items.length > 0 ? (
|
||||||
<SelectItem key={pack.id} value={pack.id}>
|
packsData.items.map((pack) => (
|
||||||
{pack.title}
|
<SelectItem key={pack.id} value={pack.id}>
|
||||||
</SelectItem>
|
{pack.title || pack.id}
|
||||||
))}
|
</SelectItem>
|
||||||
|
))
|
||||||
|
) : null}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -387,10 +387,10 @@ export default function UsersPage() {
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Packs Owned</Label>
|
<Label>Packs Owned</Label>
|
||||||
<div className="border rounded-lg max-h-[200px] overflow-y-auto p-2">
|
<div className="border rounded-lg max-h-[200px] overflow-y-auto p-2">
|
||||||
{packsData?.items.length === 0 ? (
|
{!packsData?.items || packsData.items.length === 0 ? (
|
||||||
<div className="text-sm text-muted-foreground">No packs available</div>
|
<div className="text-sm text-muted-foreground">No packs available</div>
|
||||||
) : (
|
) : (
|
||||||
packsData?.items.map((pack) => (
|
packsData.items.map((pack) => (
|
||||||
<div key={pack.id} className="flex items-center space-x-2 py-1">
|
<div key={pack.id} className="flex items-center space-x-2 py-1">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id={`pack-${pack.id}`}
|
id={`pack-${pack.id}`}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue