Update files

This commit is contained in:
glpshchn 2025-11-11 03:54:39 +03:00
parent 2bb573b919
commit f9ff325c8a
2 changed files with 97 additions and 60 deletions

View File

@ -12,7 +12,6 @@ const AdminConfirmationSchema = new mongoose.Schema({
}, },
adminNumber: { adminNumber: {
type: Number, type: Number,
required: true,
min: 1, min: 1,
max: 10 max: 10
}, },

View File

@ -167,6 +167,9 @@ export default function App() {
loadReports(); loadReports();
} else if (tab === 'admins') { } else if (tab === 'admins') {
loadAdmins(); loadAdmins();
} else if (tab === 'publish') {
// Загрузить список админов для проверки прав публикации
loadAdmins();
} else if (tab === 'chat' && user) { } else if (tab === 'chat' && user) {
initChat(); initChat();
} }
@ -278,8 +281,16 @@ export default function App() {
const initChat = () => { const initChat = () => {
if (!user || chatSocketRef.current) return; if (!user || chatSocketRef.current) return;
const socket = io('/mod-chat', {
transports: ['websocket', 'polling'] const API_URL = import.meta.env.VITE_API_URL || (
import.meta.env.PROD ? window.location.origin : 'http://localhost:3000'
);
const socket = io(`${API_URL}/mod-chat`, {
transports: ['websocket', 'polling'],
reconnection: true,
reconnectionDelay: 1000,
reconnectionAttempts: 5
}); });
socket.on('connect', () => { socket.on('connect', () => {
@ -626,67 +637,94 @@ export default function App() {
</div> </div>
); );
const renderPublish = () => ( const renderPublish = () => {
<div className="card"> // Найти админа текущего пользователя
<div className="section-header"> const currentAdmin = adminsData.admins.find((admin) => admin.telegramId === user.telegramId);
<h2>Публикация в @reichenbfurry</h2> const canPublish = currentAdmin && currentAdmin.adminNumber >= 1 && currentAdmin.adminNumber <= 10;
</div>
<div className="publish-form"> return (
<label> <div className="card">
Описание <div className="section-header">
<textarea <h2>Публикация в @reichenbfurry</h2>
value={publishState.description} </div>
onChange={(e) =>
setPublishState((prev) => ({ ...prev, description: e.target.value })) {!canPublish && (
} <div style={{ padding: '16px', backgroundColor: 'var(--bg-secondary)', borderRadius: '8px', marginBottom: '16px', color: 'var(--text-secondary)' }}>
maxLength={1024} Публиковать в канал могут только админы с номерами от 1 до 10.
placeholder="Текст поста" {currentAdmin ? (
/> <div style={{ marginTop: '8px' }}>
</label> Ваш номер: <strong>#{currentAdmin.adminNumber}</strong> (доступ запрещён)
<label>
Теги (через пробел или запятую)
<input
type="text"
value={publishState.tags}
onChange={(e) => setPublishState((prev) => ({ ...prev, tags: e.target.value }))}
placeholder="#furry #art"
/>
</label>
<label>
Номер администратора (#a1 - #a10)
<select
value={publishState.slot}
onChange={(e) =>
setPublishState((prev) => ({ ...prev, slot: parseInt(e.target.value, 10) }))
}
>
{slotOptions.map((option) => (
<option key={option} value={option}>
#{`a${option}`}
</option>
))}
</select>
</label>
<label>
Медиа (до 10, фото или видео)
<input type="file" accept="image/*,video/*" multiple onChange={handleFileChange} />
</label>
{publishState.files.length > 0 && (
<div className="file-list">
{publishState.files.map((file, index) => (
<div key={index} className="file-item">
{file.name} ({Math.round(file.size / 1024)} KB)
</div> </div>
))} ) : (
<div style={{ marginTop: '8px' }}>
Вам не присвоен номер админа. Обратитесь к владельцу.
</div>
)}
</div> </div>
)} )}
<button className="btn primary" disabled={publishing} onClick={handlePublish}>
{publishing ? <Loader2 className="spin" size={18} /> : <SendHorizontal size={18} />} <div className="publish-form">
Опубликовать <label>
</button> Описание
<textarea
value={publishState.description}
onChange={(e) =>
setPublishState((prev) => ({ ...prev, description: e.target.value }))
}
maxLength={1024}
placeholder="Текст поста"
disabled={!canPublish}
/>
</label>
<label>
Теги (через пробел или запятую)
<input
type="text"
value={publishState.tags}
onChange={(e) => setPublishState((prev) => ({ ...prev, tags: e.target.value }))}
placeholder="#furry #art"
disabled={!canPublish}
/>
</label>
{currentAdmin && (
<div style={{ padding: '12px', backgroundColor: 'var(--bg-secondary)', borderRadius: '8px', marginBottom: '8px' }}>
Ваш номер админа: <strong>#{currentAdmin.adminNumber}</strong>
<div style={{ fontSize: '12px', color: 'var(--text-secondary)', marginTop: '4px' }}>
Автоматически будет добавлен тег #a{currentAdmin.adminNumber}
</div>
</div>
)}
<label>
Медиа (до 10, фото или видео)
<input
type="file"
accept="image/*,video/*"
multiple
onChange={handleFileChange}
disabled={!canPublish}
/>
</label>
{publishState.files.length > 0 && (
<div className="file-list">
{publishState.files.map((file, index) => (
<div key={index} className="file-item">
{file.name} ({Math.round(file.size / 1024)} KB)
</div>
))}
</div>
)}
<button
className="btn primary"
disabled={publishing || !canPublish}
onClick={handlePublish}
>
{publishing ? <Loader2 className="spin" size={18} /> : <SendHorizontal size={18} />}
Опубликовать
</button>
</div>
</div> </div>
</div> );
); };
const renderAdmins = () => ( const renderAdmins = () => (
<div className="card"> <div className="card">