feat: add broadcast category selector (system/news/promo) in admin UI

This commit is contained in:
c0mrade
2026-04-10 17:04:22 +03:00
parent e6f6713b0e
commit 362a69812f
2 changed files with 41 additions and 0 deletions

View File

@@ -76,6 +76,8 @@ export interface EmailBroadcastCreateRequest {
export interface CombinedBroadcastCreateRequest { export interface CombinedBroadcastCreateRequest {
channel: BroadcastChannel; channel: BroadcastChannel;
target: string; target: string;
// Broadcast category for user notification preference filtering
category?: 'system' | 'news' | 'promo';
// Telegram fields // Telegram fields
message_text?: string; message_text?: string;
selected_buttons?: string[]; selected_buttons?: string[];
@@ -111,6 +113,8 @@ export interface Broadcast {
created_at: string; created_at: string;
completed_at: string | null; completed_at: string | null;
progress_percent: number; progress_percent: number;
// Broadcast category
category?: 'system' | 'news' | 'promo';
// New fields for channel support // New fields for channel support
channel?: BroadcastChannel; channel?: BroadcastChannel;
email_subject?: string | null; email_subject?: string | null;

View File

@@ -128,6 +128,9 @@ export default function AdminBroadcastCreate() {
const [showTelegramFilters, setShowTelegramFilters] = useState(false); const [showTelegramFilters, setShowTelegramFilters] = useState(false);
const [showEmailFilters, setShowEmailFilters] = useState(false); const [showEmailFilters, setShowEmailFilters] = useState(false);
// Broadcast category (system/news/promo)
const [category, setCategory] = useState<'system' | 'news' | 'promo'>('system');
// Telegram-specific state // Telegram-specific state
const [messageText, setMessageText] = useState(''); const [messageText, setMessageText] = useState('');
const [selectedButtons, setSelectedButtons] = useState<string[]>(['home']); const [selectedButtons, setSelectedButtons] = useState<string[]>(['home']);
@@ -395,6 +398,7 @@ export default function AdminBroadcastCreate() {
message_text: messageText, message_text: messageText,
selected_buttons: selectedButtons, selected_buttons: selectedButtons,
custom_buttons: customButtons.length > 0 ? customButtons : undefined, custom_buttons: customButtons.length > 0 ? customButtons : undefined,
category,
}; };
if (uploadedFileId) { if (uploadedFileId) {
data.media = { type: mediaType, file_id: uploadedFileId }; data.media = { type: mediaType, file_id: uploadedFileId };
@@ -409,6 +413,7 @@ export default function AdminBroadcastCreate() {
target: emailTarget, target: emailTarget,
email_subject: emailSubject, email_subject: emailSubject,
email_html_content: emailContent, email_html_content: emailContent,
category,
}; };
createMutation.mutate(data); createMutation.mutate(data);
return; return;
@@ -423,6 +428,7 @@ export default function AdminBroadcastCreate() {
message_text: messageText, message_text: messageText,
selected_buttons: selectedButtons, selected_buttons: selectedButtons,
custom_buttons: customButtons.length > 0 ? customButtons : undefined, custom_buttons: customButtons.length > 0 ? customButtons : undefined,
category,
}; };
if (uploadedFileId) { if (uploadedFileId) {
telegramData.media = { type: mediaType, file_id: uploadedFileId }; telegramData.media = { type: mediaType, file_id: uploadedFileId };
@@ -433,6 +439,7 @@ export default function AdminBroadcastCreate() {
target: emailTarget, target: emailTarget,
email_subject: emailSubject, email_subject: emailSubject,
email_html_content: emailContent, email_html_content: emailContent,
category,
}; };
await adminBroadcastsApi.createCombined(telegramData); await adminBroadcastsApi.createCombined(telegramData);
@@ -583,6 +590,36 @@ export default function AdminBroadcastCreate() {
)} )}
</div> </div>
{/* Broadcast category */}
<div className="card">
<label className="mb-3 block text-sm font-medium text-dark-300">
{t('admin.broadcasts.category', 'Категория рассылки')}
</label>
<p className="mb-3 text-xs text-dark-500">
{t(
'admin.broadcasts.categoryDesc',
'Пользователи могут отключить получение новостей и промо в настройках профиля. Системные рассылки доставляются всем.',
)}
</p>
<div className="flex gap-3">
{(['system', 'news', 'promo'] as const).map((cat) => (
<button
key={cat}
onClick={() => setCategory(cat)}
className={`flex-1 rounded-lg border p-3 text-sm font-medium transition-all ${
category === cat
? 'border-accent-500 bg-accent-500/10 text-accent-400'
: 'border-dark-700 bg-dark-800 text-dark-300 hover:border-dark-600'
}`}
>
{cat === 'system' && t('admin.broadcasts.categorySystem', '⚙️ Системное')}
{cat === 'news' && t('admin.broadcasts.categoryNews', '📰 Новости')}
{cat === 'promo' && t('admin.broadcasts.categoryPromo', '🎁 Промо')}
</button>
))}
</div>
</div>
{/* Telegram section */} {/* Telegram section */}
{telegramEnabled && ( {telegramEnabled && (
<div className="card space-y-6"> <div className="card space-y-6">