voices
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Web App CI / test (push) Waiting to run
Web App CI / build (push) Blocked by required conditions
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
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Web App CI / test (push) Waiting to run
Web App CI / build (push) Blocked by required conditions
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
d8a29eb84a
commit
47005a357a
7 changed files with 80 additions and 18 deletions
|
|
@ -11,17 +11,49 @@ export async function upsertCardWithOptionalVoice(
|
|||
card: GameCardDto,
|
||||
voice?: PendingVoiceUpload,
|
||||
): Promise<{ success: boolean; card: GameCardDto }> {
|
||||
console.log('🔍 upsertCardWithOptionalVoice: Starting', {
|
||||
cardId: card.id,
|
||||
hasVoice: !!voice,
|
||||
voiceUrl: voice?.voiceUrl,
|
||||
language: voice?.language,
|
||||
})
|
||||
|
||||
const response = await cardsApi.upsertCard(card)
|
||||
|
||||
const responseCardId = response.card?.id != null ? String(response.card.id) : ''
|
||||
const requestCardId = card.id != null ? String(card.id) : ''
|
||||
const cardId = responseCardId || requestCardId
|
||||
|
||||
console.log('🔍 upsertCardWithOptionalVoice: After upsertCard', {
|
||||
responseCardId,
|
||||
requestCardId,
|
||||
cardId,
|
||||
hasVoice: !!voice,
|
||||
voiceUrl: voice?.voiceUrl,
|
||||
})
|
||||
|
||||
if (!voice || !voice.voiceUrl || !cardId) {
|
||||
console.log('⚠️ upsertCardWithOptionalVoice: Skipping voice link', {
|
||||
hasVoice: !!voice,
|
||||
voiceUrl: voice?.voiceUrl,
|
||||
cardId,
|
||||
})
|
||||
return response
|
||||
}
|
||||
|
||||
await voicesApi.addCardVoice(cardId, voice.voiceUrl, voice.language)
|
||||
console.log('✅ upsertCardWithOptionalVoice: Calling addCardVoice', {
|
||||
cardId,
|
||||
voiceUrl: voice.voiceUrl,
|
||||
language: voice.language,
|
||||
})
|
||||
|
||||
try {
|
||||
await voicesApi.addCardVoice(cardId, voice.voiceUrl, voice.language)
|
||||
console.log('✅ upsertCardWithOptionalVoice: Successfully added voice')
|
||||
} catch (error) {
|
||||
console.error('❌ upsertCardWithOptionalVoice: Error adding voice', error)
|
||||
throw error
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,16 @@ export function CardVoicesManager({ cardId, disabled = false }: CardVoicesManage
|
|||
|
||||
// Add voice mutation
|
||||
const addVoiceMutation = useMutation({
|
||||
mutationFn: ({ voiceUrl, language }: { voiceUrl: string; language: string }) =>
|
||||
voicesApi.addCardVoice(cardId, voiceUrl, language),
|
||||
mutationFn: ({ voiceUrl, language }: { voiceUrl: string; language: string }) => {
|
||||
console.log('🔍 CardVoicesManager: addVoiceMutation.mutationFn called', {
|
||||
cardId,
|
||||
voiceUrl,
|
||||
language,
|
||||
})
|
||||
return voicesApi.addCardVoice(cardId, voiceUrl, language)
|
||||
},
|
||||
onSuccess: () => {
|
||||
console.log('✅ CardVoicesManager: addVoiceMutation.onSuccess')
|
||||
queryClient.invalidateQueries({ queryKey: ['cardVoices', cardId] })
|
||||
toast.success('Voice added successfully')
|
||||
setShowAddForm(false)
|
||||
|
|
@ -40,6 +47,7 @@ export function CardVoicesManager({ cardId, disabled = false }: CardVoicesManage
|
|||
setNewLanguage('en')
|
||||
},
|
||||
onError: (error: unknown) => {
|
||||
console.error('❌ CardVoicesManager: addVoiceMutation.onError', error)
|
||||
const axiosError = error as AxiosError<{ message?: string }>
|
||||
toast.error(axiosError.response?.data?.message || 'Failed to add voice')
|
||||
},
|
||||
|
|
@ -59,11 +67,24 @@ export function CardVoicesManager({ cardId, disabled = false }: CardVoicesManage
|
|||
})
|
||||
|
||||
const handleAddVoice = () => {
|
||||
console.log('🔍 CardVoicesManager: handleAddVoice called', {
|
||||
newAudio,
|
||||
newLanguage,
|
||||
cardId,
|
||||
})
|
||||
|
||||
if (!newAudio) {
|
||||
console.warn('⚠️ CardVoicesManager: newAudio is empty')
|
||||
toast.error('Please upload an audio file')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('✅ CardVoicesManager: Calling addVoiceMutation.mutate', {
|
||||
cardId,
|
||||
voiceUrl: newAudio,
|
||||
language: newLanguage,
|
||||
})
|
||||
|
||||
addVoiceMutation.mutate({
|
||||
voiceUrl: newAudio,
|
||||
language: newLanguage,
|
||||
|
|
@ -103,7 +124,10 @@ export function CardVoicesManager({ cardId, disabled = false }: CardVoicesManage
|
|||
<AudioUpload
|
||||
label="Audio File"
|
||||
value={newAudio}
|
||||
onChange={setNewAudio}
|
||||
onChange={(value) => {
|
||||
console.log('🔍 CardVoicesManager: AudioUpload onChange', { value, cardId })
|
||||
setNewAudio(value)
|
||||
}}
|
||||
language={newLanguage}
|
||||
onLanguageChange={setNewLanguage}
|
||||
disabled={disabled || addVoiceMutation.isPending}
|
||||
|
|
|
|||
|
|
@ -868,6 +868,8 @@ class AdminCardsApiV2 {
|
|||
|
||||
// Create voice record with object ID
|
||||
print('🔍 addCardVoice: Creating voice record with objectId $objectId for card $cardId');
|
||||
print('🔍 addCardVoice: VoiceModelsCompanion.insert params: cardId=$cardId, voiceUrl=$objectId, language=${requestDto.language ?? 'en'}');
|
||||
|
||||
final voiceId = await _db.packDao.createVoice(
|
||||
VoiceModelsCompanion.insert(
|
||||
cardId: cardId,
|
||||
|
|
@ -881,6 +883,10 @@ class AdminCardsApiV2 {
|
|||
print('🔍 addCardVoice: Linking voice $voiceId to card $cardId');
|
||||
await _db.packDao.addVoiceToCard(cardId, voiceId);
|
||||
print('✅ addCardVoice: Successfully linked voice $voiceId to card $cardId');
|
||||
|
||||
// Verify the link was created
|
||||
final verifyVoices = await _db.packDao.getCardVoices(cardId);
|
||||
print('🔍 addCardVoice: Verification - found ${verifyVoices.length} voices for card $cardId');
|
||||
|
||||
final voice = await _db.packDao.getVoiceById(voiceId);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
|||
import 'package:yx_scope_flutter/yx_scope_flutter.dart';
|
||||
|
||||
import '../../../di/app_scope/app_scope_container.dart';
|
||||
import '../../../domain/config/api_config_v2.dart';
|
||||
import '../../../presentation/theme/app_colors.dart';
|
||||
import '../../../presentation/widgets/pack_card_item.dart';
|
||||
import '../../../presentation/widgets/pack_details_header.dart';
|
||||
|
|
@ -20,6 +19,7 @@ import '../../../presentation/widgets/card_viewer.dart';
|
|||
import '../../../presentation/widgets/shuffle_animated_switcher.dart';
|
||||
import '../../../presentation/widgets/shuffle_movement_wrapper.dart';
|
||||
import '../../../presentation/widgets/utils/card_movement_utils.dart';
|
||||
import '../../../utils/card_image_utils.dart';
|
||||
import '../../../utils/color_extension.dart';
|
||||
import '../../../utils/responsive.dart';
|
||||
|
||||
|
|
@ -823,8 +823,8 @@ class _PackDetailsPageState extends State<PackDetailsPage> {
|
|||
|
||||
/// Изображение карточки (вынесено в отдельный метод для переиспользования)
|
||||
Widget _buildCardImage(GameCardDto card, double width, double height) {
|
||||
// Use presigned URL from DTO
|
||||
final imageUrl = card.imageUrl;
|
||||
// Use helper to get image URL (handles imageUrl, image URL, and filename)
|
||||
final imageUrl = CardImageUtils.getCardImageUrl(card, widget.packId);
|
||||
|
||||
if (imageUrl == null || imageUrl.isEmpty) {
|
||||
return Center(
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ import 'package:mnemo_cards_web_v2/di/user_scope/user_scope.dart';
|
|||
import 'package:yx_scope_flutter/yx_scope_flutter.dart';
|
||||
import 'package:yx_state_flutter/yx_state_flutter.dart';
|
||||
|
||||
import '../../../domain/config/api_config_v2.dart';
|
||||
import '../../../domain/state/card_flipper_state_manager.dart';
|
||||
import '../../../presentation/widgets/card_voice_controls.dart';
|
||||
import '../../../presentation/widgets/mnemo_text.dart';
|
||||
import '../../../utils/card_image_utils.dart';
|
||||
|
||||
/// Card flipper widget for studying cards
|
||||
///
|
||||
|
|
@ -720,8 +720,8 @@ class _CardSide extends StatelessWidget {
|
|||
}
|
||||
|
||||
Widget _buildImage() {
|
||||
// Use presigned URL from DTO
|
||||
final imageUrl = card.imageUrl;
|
||||
// Use helper to get image URL (handles imageUrl, image URL, and filename)
|
||||
final imageUrl = CardImageUtils.getCardImageUrl(card, packId);
|
||||
|
||||
if (imageUrl == null || imageUrl.isEmpty) {
|
||||
return Container(
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
||||
|
||||
import '../../domain/config/api_config_v2.dart';
|
||||
import '../../presentation/theme/app_colors.dart';
|
||||
import '../../utils/card_image_utils.dart';
|
||||
import 'card_favorite_button.dart';
|
||||
import 'card_voice_controls.dart';
|
||||
import 'mnemo_text.dart';
|
||||
|
|
@ -565,8 +565,8 @@ class _CardSide extends StatelessWidget {
|
|||
}
|
||||
|
||||
Widget _buildImage() {
|
||||
// Use presigned URL from DTO
|
||||
final imageUrl = card.imageUrl;
|
||||
// Use helper to get image URL (handles imageUrl, image URL, and filename)
|
||||
final imageUrl = CardImageUtils.getCardImageUrl(card, packId);
|
||||
|
||||
if (imageUrl == null || imageUrl.isEmpty) {
|
||||
return Container(
|
||||
|
|
@ -600,8 +600,8 @@ class _CardSide extends StatelessWidget {
|
|||
}
|
||||
|
||||
Widget _buildImageBack() {
|
||||
// Use presigned URL from DTO
|
||||
final imageBackUrl = card.imageBackUrl;
|
||||
// Use helper to get back image URL (handles imageBackUrl, imageBack URL, and filename)
|
||||
final imageBackUrl = CardImageUtils.getCardImageBackUrl(card, packId);
|
||||
|
||||
if (imageBackUrl == null || imageBackUrl.isEmpty) {
|
||||
return Container(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import 'dart:math';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
||||
|
||||
import '../../domain/config/api_config_v2.dart';
|
||||
import '../../utils/card_image_utils.dart';
|
||||
import 'mnemo_text.dart';
|
||||
|
||||
/// Виджет для отображения отдельной карточки в сетке
|
||||
|
|
@ -260,8 +260,8 @@ class PackCardItem extends StatelessWidget {
|
|||
/// Отображает изображение карточки
|
||||
/// Загружает изображение с бэкенда по URL
|
||||
Widget _buildImage(BuildContext context, double cardWidth, double cardHeight) {
|
||||
// Use presigned URL from DTO
|
||||
final imageUrl = card.imageUrl;
|
||||
// Use helper to get image URL (handles imageUrl, image URL, and filename)
|
||||
final imageUrl = CardImageUtils.getCardImageUrl(card, packId);
|
||||
|
||||
if (imageUrl == null || imageUrl.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
|
|
|
|||
Loading…
Reference in a new issue