mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 10:42:57 +00:00
dev day #65,5
This commit is contained in:
@@ -36,6 +36,12 @@ const MatchLinkBadge: React.FC<{ articleId: number }> = ({ articleId }) => {
|
||||
staleTime: 60_000,
|
||||
retry: false,
|
||||
});
|
||||
|
||||
// Show loading state while fetching
|
||||
if (linkQ.isLoading) {
|
||||
return <Badge colorScheme="gray">Načítání...</Badge>;
|
||||
}
|
||||
|
||||
const mid = (linkQ.data as any)?.external_match_id;
|
||||
if (!mid) return <Badge colorScheme="gray">Nepropojeno</Badge>;
|
||||
|
||||
@@ -651,38 +657,19 @@ const ArticlesAdminPage = () => {
|
||||
// Forward the payload as-is so new fields (youtube, gallery) are persisted
|
||||
createArticle(payload),
|
||||
onSuccess: async (created: any) => {
|
||||
try {
|
||||
// If a match was selected (from temp storage), link it now that we have an article ID
|
||||
const matchRaw = tempMatchLink || matchIdInput;
|
||||
const matchToLink = typeof matchRaw === 'string' ? matchRaw : String(matchRaw || '');
|
||||
const matchId = matchToLink.trim();
|
||||
if (matchId && created?.id) {
|
||||
await putArticleMatchLink(created.id, { external_match_id: matchId, title: (editing as any)?.title || '' });
|
||||
setLinkedMatchId(matchId);
|
||||
toast({
|
||||
title: 'Článek vytvořen a propojen se zápasem',
|
||||
description: `Match ID: ${matchId}`,
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
isClosable: true
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: 'Článek byl úspěšně vytvořen',
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
isClosable: true
|
||||
});
|
||||
}
|
||||
// Clear temporary storage after successful creation
|
||||
setTempMatchLink('');
|
||||
} finally {
|
||||
qc.invalidateQueries({ queryKey: ['admin-articles'] });
|
||||
qc.invalidateQueries({ queryKey: ['articles'] });
|
||||
qc.invalidateQueries({ queryKey: ['recentArticles'] });
|
||||
qc.invalidateQueries({ queryKey: ['article-match-link'] }); // Invalidate match links
|
||||
closeModal();
|
||||
}
|
||||
console.log('Article created successfully in mutation callback:', created);
|
||||
// Note: Match linking is now handled in onSubmit() to avoid race conditions
|
||||
// Clear temporary storage
|
||||
setTempMatchLink('');
|
||||
setMatchIdInput('');
|
||||
|
||||
// Invalidate queries to refresh the list
|
||||
qc.invalidateQueries({ queryKey: ['admin-articles'] });
|
||||
qc.invalidateQueries({ queryKey: ['articles'] });
|
||||
qc.invalidateQueries({ queryKey: ['recentArticles'] });
|
||||
qc.invalidateQueries({ queryKey: ['article-match-link'] }); // Invalidate match links
|
||||
|
||||
// Don't close modal here - let onSubmit handle it after match linking
|
||||
},
|
||||
onError: (e: any) => {
|
||||
console.error('Error creating article:', e);
|
||||
@@ -702,18 +689,16 @@ const ArticlesAdminPage = () => {
|
||||
updateArticle(id, payload),
|
||||
onSuccess: (_, variables) => {
|
||||
const articleId = variables.id;
|
||||
toast({
|
||||
title: 'Článek byl úspěšně aktualizován',
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
isClosable: true
|
||||
});
|
||||
console.log('Article updated successfully in mutation callback:', articleId);
|
||||
|
||||
// Invalidate queries to refresh the list
|
||||
qc.invalidateQueries({ queryKey: ['admin-articles'] });
|
||||
qc.invalidateQueries({ queryKey: ['articles'] });
|
||||
qc.invalidateQueries({ queryKey: ['recentArticles'] });
|
||||
qc.invalidateQueries({ queryKey: ['article-match-link', articleId] }); // Invalidate specific match link
|
||||
qc.invalidateQueries({ queryKey: ['article', `id:${articleId}`] }); // Invalidate article detail
|
||||
closeModal();
|
||||
|
||||
// Success toast and modal closing handled in onSubmit()
|
||||
},
|
||||
onError: (e: any) => {
|
||||
console.error('Error updating article:', e);
|
||||
@@ -864,7 +849,7 @@ const ArticlesAdminPage = () => {
|
||||
} catch { return undefined; }
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
const onSubmit = async (options: { keepOpen?: boolean } = {}) => {
|
||||
if (!editing) return;
|
||||
// Require category selection by name (kategorie je povinná)
|
||||
if (!String((editing as any)?.category_name || '').trim()) {
|
||||
@@ -932,10 +917,83 @@ const ArticlesAdminPage = () => {
|
||||
// Log the payload for debugging
|
||||
console.log('Saving article with payload:', JSON.stringify(payload, null, 2));
|
||||
|
||||
// Debug: Log match link state before submission
|
||||
console.log('Match link state before submit:', {
|
||||
tempMatchLink,
|
||||
matchIdInput,
|
||||
linkedMatchId,
|
||||
isNewArticle: !(editing as any)?.id
|
||||
});
|
||||
|
||||
if ((editing as any)?.id) {
|
||||
// Update existing article
|
||||
await updateMut.mutateAsync({ id: (editing as any).id, payload });
|
||||
|
||||
// Handle match linking for existing articles (update or delete)
|
||||
const matchRaw = matchIdInput || linkedMatchId;
|
||||
const matchId = String(matchRaw || '').trim();
|
||||
let matchLinked = false;
|
||||
if (matchId) {
|
||||
try {
|
||||
await putArticleMatchLink((editing as any).id, { external_match_id: matchId, title: editing.title || '' });
|
||||
console.log('Match link updated for existing article');
|
||||
matchLinked = true;
|
||||
} catch (err: any) {
|
||||
console.error('Failed to update match link:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// Show success message
|
||||
toast({
|
||||
title: matchLinked ? 'Článek aktualizován a propojen se zápasem' : 'Článek byl úspěšně aktualizován',
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
isClosable: true
|
||||
});
|
||||
} else {
|
||||
await createMut.mutateAsync(payload);
|
||||
// Create new article
|
||||
const created = await createMut.mutateAsync(payload);
|
||||
|
||||
// Handle match linking for new articles
|
||||
const matchRaw = tempMatchLink || matchIdInput;
|
||||
const matchId = String(matchRaw || '').trim();
|
||||
if (matchId && created?.id) {
|
||||
console.log('Linking new article', created.id, 'with match', matchId);
|
||||
try {
|
||||
await putArticleMatchLink(created.id, { external_match_id: matchId, title: editing.title || '' });
|
||||
console.log('Match link created for new article');
|
||||
setLinkedMatchId(matchId);
|
||||
toast({
|
||||
title: 'Článek vytvořen a propojen se zápasem',
|
||||
description: `Match ID: ${matchId}`,
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
isClosable: true
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error('Failed to link match:', err);
|
||||
toast({
|
||||
title: 'Článek vytvořen, ale propojení se zápasem selhalo',
|
||||
description: err?.response?.data?.error || err?.message || 'Zkuste propojit zápas ručně',
|
||||
status: 'warning',
|
||||
duration: 5000,
|
||||
isClosable: true
|
||||
});
|
||||
}
|
||||
} else if (created?.id) {
|
||||
// No match to link, just show success
|
||||
toast({
|
||||
title: 'Článek byl úspěšně vytvořen',
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
isClosable: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Close modal after successful save (unless keepOpen is true)
|
||||
if (!options.keepOpen) {
|
||||
closeModal();
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
@@ -1781,13 +1839,30 @@ const ArticlesAdminPage = () => {
|
||||
qc.invalidateQueries({ queryKey: ['linked-polls'] });
|
||||
}} />
|
||||
) : (
|
||||
<Alert status="info" borderRadius="md">
|
||||
<Alert status="warning" borderRadius="md">
|
||||
<AlertIcon />
|
||||
<VStack align="start" spacing={1}>
|
||||
<Text fontWeight="semibold">Nejprve uložte článek</Text>
|
||||
<VStack align="start" spacing={2}>
|
||||
<Text fontWeight="semibold">Článek ještě není uložen</Text>
|
||||
<Text fontSize="sm">
|
||||
Pro vytvoření nebo propojení ankety nejprve uložte článek tlačítkem "Uložit" níže. Poté se vrátíte do úprav a budete moci přidat ankety.
|
||||
Pro propojení anket s článkem musíte nejprve článek uložit. Klikněte na "Uložit" níže - článek se uloží jako koncept a poté budete moci přidat ankety.
|
||||
</Text>
|
||||
<Button
|
||||
size="sm"
|
||||
colorScheme="blue"
|
||||
onClick={async () => {
|
||||
// Save article as draft first, keep modal open
|
||||
try {
|
||||
await onSubmit({ keepOpen: true });
|
||||
// Switch to poll tab after save
|
||||
setActiveTabIndex(5); // Poll tab is index 5
|
||||
} catch (error) {
|
||||
// Error is handled by onSubmit
|
||||
}
|
||||
}}
|
||||
isLoading={createMut.isLoading}
|
||||
>
|
||||
Uložit jako koncept a přidat ankety
|
||||
</Button>
|
||||
</VStack>
|
||||
</Alert>
|
||||
)}
|
||||
@@ -1798,7 +1873,7 @@ const ArticlesAdminPage = () => {
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant="ghost" mr={3} onClick={closeModal}>Zrušit</Button>
|
||||
<Button colorScheme="blue" onClick={onSubmit} isLoading={createMut.isLoading || updateMut.isLoading}>Uložit</Button>
|
||||
<Button colorScheme="blue" onClick={() => onSubmit()} isLoading={createMut.isLoading || updateMut.isLoading}>Uložit</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user