Update files
This commit is contained in:
parent
2bb573b919
commit
f9ff325c8a
|
|
@ -12,7 +12,6 @@ const AdminConfirmationSchema = new mongoose.Schema({
|
|||
},
|
||||
adminNumber: {
|
||||
type: Number,
|
||||
required: true,
|
||||
min: 1,
|
||||
max: 10
|
||||
},
|
||||
|
|
|
|||
|
|
@ -167,6 +167,9 @@ export default function App() {
|
|||
loadReports();
|
||||
} else if (tab === 'admins') {
|
||||
loadAdmins();
|
||||
} else if (tab === 'publish') {
|
||||
// Загрузить список админов для проверки прав публикации
|
||||
loadAdmins();
|
||||
} else if (tab === 'chat' && user) {
|
||||
initChat();
|
||||
}
|
||||
|
|
@ -278,8 +281,16 @@ export default function App() {
|
|||
|
||||
const initChat = () => {
|
||||
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', () => {
|
||||
|
|
@ -626,67 +637,94 @@ export default function App() {
|
|||
</div>
|
||||
);
|
||||
|
||||
const renderPublish = () => (
|
||||
<div className="card">
|
||||
<div className="section-header">
|
||||
<h2>Публикация в @reichenbfurry</h2>
|
||||
</div>
|
||||
<div className="publish-form">
|
||||
<label>
|
||||
Описание
|
||||
<textarea
|
||||
value={publishState.description}
|
||||
onChange={(e) =>
|
||||
setPublishState((prev) => ({ ...prev, description: e.target.value }))
|
||||
}
|
||||
maxLength={1024}
|
||||
placeholder="Текст поста"
|
||||
/>
|
||||
</label>
|
||||
<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)
|
||||
const renderPublish = () => {
|
||||
// Найти админа текущего пользователя
|
||||
const currentAdmin = adminsData.admins.find((admin) => admin.telegramId === user.telegramId);
|
||||
const canPublish = currentAdmin && currentAdmin.adminNumber >= 1 && currentAdmin.adminNumber <= 10;
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
<div className="section-header">
|
||||
<h2>Публикация в @reichenbfurry</h2>
|
||||
</div>
|
||||
|
||||
{!canPublish && (
|
||||
<div style={{ padding: '16px', backgroundColor: 'var(--bg-secondary)', borderRadius: '8px', marginBottom: '16px', color: 'var(--text-secondary)' }}>
|
||||
⚠️ Публиковать в канал могут только админы с номерами от 1 до 10.
|
||||
{currentAdmin ? (
|
||||
<div style={{ marginTop: '8px' }}>
|
||||
Ваш номер: <strong>#{currentAdmin.adminNumber}</strong> (доступ запрещён)
|
||||
</div>
|
||||
))}
|
||||
) : (
|
||||
<div style={{ marginTop: '8px' }}>
|
||||
Вам не присвоен номер админа. Обратитесь к владельцу.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<button className="btn primary" disabled={publishing} onClick={handlePublish}>
|
||||
{publishing ? <Loader2 className="spin" size={18} /> : <SendHorizontal size={18} />}
|
||||
Опубликовать
|
||||
</button>
|
||||
|
||||
<div className="publish-form">
|
||||
<label>
|
||||
Описание
|
||||
<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>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
const renderAdmins = () => (
|
||||
<div className="card">
|
||||
|
|
|
|||
Loading…
Reference in New Issue