mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-05 11:12:56 +00:00
de day #74
This commit is contained in:
@@ -40,7 +40,7 @@ import {
|
||||
useColorModeValue,
|
||||
Image as ChakraImage,
|
||||
} from '@chakra-ui/react';
|
||||
import { FiEdit2, FiPlus, FiTrash2 } from 'react-icons/fi';
|
||||
import { FiEdit2, FiPlus, FiTrash2, FiLink } from 'react-icons/fi';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { Event } from '../../types/event';
|
||||
import { uploadFile } from '../../services/articles';
|
||||
@@ -60,9 +60,10 @@ import { getCachedYouTube, YouTubeVideo } from '../../services/youtube';
|
||||
import SaveStatusIndicator from '../../components/common/SaveStatusIndicator';
|
||||
import DraftRecoveryModal from '../../components/common/DraftRecoveryModal';
|
||||
import { useAutoSave, loadDraft, getDraftMetadata } from '../../hooks/useAutoSave';
|
||||
import { FiVideo, FiYoutube, FiLink } from 'react-icons/fi';
|
||||
import { FiVideo, FiYoutube } from 'react-icons/fi';
|
||||
import ThumbnailPreview from '../../components/common/ThumbnailPreview';
|
||||
import { assetUrl } from '../../utils/url';
|
||||
import { createShortLink } from '../../services/shortlinks';
|
||||
|
||||
const types: Array<{ value: Event['type']; label: string }> = [
|
||||
{ value: 'match', label: 'Zápas' },
|
||||
@@ -124,6 +125,13 @@ const AdminActivitiesPage: React.FC = () => {
|
||||
});
|
||||
const events = data || [];
|
||||
|
||||
// Localized label for event type
|
||||
const typeLabel = (t?: string) => {
|
||||
const v = String(t || '').trim() as any;
|
||||
const found = types.find((x) => x.value === v);
|
||||
return found ? found.label : 'Jiné';
|
||||
};
|
||||
|
||||
// Load club YouTube videos
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
@@ -266,22 +274,18 @@ const AdminActivitiesPage: React.FC = () => {
|
||||
const e = editing || {};
|
||||
// Build a helpful Czech prompt including known fields
|
||||
const lines: string[] = [];
|
||||
const clubName = String(settingsQ?.data?.club_name || '').trim();
|
||||
if (clubName) lines.push(`Klub: ${clubName}`);
|
||||
if (e.type) lines.push(`Typ: ${e.type}`);
|
||||
if (e.location) lines.push(`Místo: ${e.location}`);
|
||||
if (e.start_time) {
|
||||
try { lines.push(`Začátek: ${new Date(e.start_time as any).toLocaleString('cs-CZ')}`); } catch {}
|
||||
}
|
||||
if (e.end_time) {
|
||||
try { lines.push(`Konec: ${new Date(e.end_time as any).toLocaleString('cs-CZ')}`); } catch {}
|
||||
}
|
||||
if (e.description) lines.push(`Poznámky: ${e.description}`);
|
||||
const base = lines.join('\n');
|
||||
const toneText = aiTone === 'informative' ? 'informativním a věcným stylem' : aiTone === 'formal' ? 'formálním a profesionálním stylem' : 'přátelským, pozitivním a lákavým stylem';
|
||||
const safeUserPrompt = (aiPrompt || 'Vytvoř krátké oznámení pro fanoušky o klubové aktivitě.').trim();
|
||||
const prompt = `${safeUserPrompt}\n\nPiš ${toneText}, česky, s důrazem na jasnost a pozvánku k účasti.\nDetaily:\n${base}`.trim();
|
||||
const constraints = 'Nevkládej datum ani místo (lokalitu) do textu. Neuváděj konkrétní čas nebo adresu.';
|
||||
const prompt = `${safeUserPrompt}\n\nPiš ${toneText}, česky, s důrazem na jasnost a pozvánku k účasti. ${constraints}\nDetaily:\n${base}`.trim();
|
||||
const { data } = await api.post('/ai/blog/generate', {
|
||||
prompt,
|
||||
audience: 'Fanoušci klubu, oznámení/pozvánka',
|
||||
audience: clubName ? `Fanoušci klubu ${clubName}, oznámení/pozvánka` : 'Fanoušci klubu, oznámení/pozvánka',
|
||||
min_words: 120,
|
||||
});
|
||||
|
||||
@@ -485,7 +489,7 @@ const AdminActivitiesPage: React.FC = () => {
|
||||
)}
|
||||
</Td>
|
||||
<Td>{ev.title}</Td>
|
||||
<Td>{ev.type}</Td>
|
||||
<Td>{typeLabel(ev.type as any)}</Td>
|
||||
<Td>{new Date(ev.start_time).toLocaleString()}</Td>
|
||||
<Td>{ev.end_time ? new Date(ev.end_time).toLocaleString() : '-'}</Td>
|
||||
<Td>{ev.location || '-'}</Td>
|
||||
@@ -494,6 +498,23 @@ const AdminActivitiesPage: React.FC = () => {
|
||||
<HStack>
|
||||
<IconButton aria-label="Upravit" size="sm" icon={<FiEdit2 />} onClick={() => openEdit(ev)} />
|
||||
<IconButton aria-label="Smazat" size="sm" colorScheme="red" icon={<FiTrash2 />} onClick={() => deleteMut.mutate(ev.id)} />
|
||||
<IconButton
|
||||
aria-label="Zkrátit odkaz"
|
||||
size="sm"
|
||||
icon={<FiLink />}
|
||||
title="Zkrátit odkaz pro sdílení"
|
||||
onClick={async () => {
|
||||
try {
|
||||
const origin = window.location.origin;
|
||||
const target = `${origin}/aktivita/${ev.id}`;
|
||||
const res = await createShortLink({ target_url: target, title: ev.title, source_type: 'event', source_id: ev.id as any });
|
||||
await navigator.clipboard.writeText(res.short_url);
|
||||
toast({ title: 'Zkrácený odkaz zkopírován', description: res.short_url, status: 'success', duration: 4000 });
|
||||
} catch (e: any) {
|
||||
toast({ title: 'Vytvoření odkazu selhalo', description: e?.message || 'Zkuste to znovu', status: 'error' });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</HStack>
|
||||
</Td>
|
||||
</Tr>
|
||||
|
||||
Reference in New Issue
Block a user