
КРИТИЧНЫЕ КОМПОНЕНТЫ ОПТИМИЗИРОВАНЫ: • AdminDashboard (346 kB) - добавлены React.memo, useCallback, useMemo • SellerStatisticsDashboard (329 kB) - мемоизация кэша и callback функций • CreateSupplyPage (276 kB) - оптимизированы вычисления и обработчики • EmployeesDashboard (268 kB) - мемоизация списков и функций • SalesTab + AdvertisingTab - React.memo обертка ТЕХНИЧЕСКИЕ УЛУЧШЕНИЯ: ✅ React.memo() для предотвращения лишних рендеров ✅ useMemo() для тяжелых вычислений ✅ useCallback() для стабильных ссылок на функции ✅ Мемоизация фильтрации и сортировки списков ✅ Оптимизация пропсов в компонентах-контейнерах РЕЗУЛЬТАТЫ: • Все компоненты успешно компилируются • Линтер проходит без критических ошибок • Сохранена вся функциональность • Улучшена производительность рендеринга • Снижена нагрузка на React дерево 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
interface S3Config {
|
||
accessKeyId: string
|
||
secretAccessKey: string
|
||
region: string
|
||
endpoint: string
|
||
bucket: string
|
||
}
|
||
|
||
const s3Config: S3Config = {
|
||
accessKeyId: 'I6XD2OR7YO2ZN6L6Z629',
|
||
secretAccessKey: '9xCOoafisG0aB9lJNvdLO1UuK73fBvMcpHMdijrJ',
|
||
region: 'ru-1',
|
||
endpoint: 'https://s3.twcstorage.ru',
|
||
bucket: '617774af-sfera',
|
||
}
|
||
|
||
export class S3Service {
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||
private static async createSignedUrl(fileName: string, fileType: string): Promise<string> {
|
||
// Для простоты пока используем прямую загрузку через fetch
|
||
// В продакшене лучше генерировать signed URLs на backend
|
||
// fileType используется для будущей логики разделения по типам файлов
|
||
const timestamp = Date.now()
|
||
const key = `avatars/${timestamp}-${fileName}`
|
||
|
||
return key
|
||
}
|
||
|
||
static async uploadAvatar(file: File, userId: string): Promise<string> {
|
||
try {
|
||
// Создаем FormData для загрузки
|
||
const formData = new FormData()
|
||
formData.append('file', file)
|
||
formData.append('userId', userId)
|
||
|
||
// Загружаем через наш API роут
|
||
const response = await fetch('/api/upload-avatar', {
|
||
method: 'POST',
|
||
body: formData,
|
||
})
|
||
|
||
if (!response.ok) {
|
||
const errorData = await response.json()
|
||
throw new Error(errorData.error || 'Failed to upload avatar')
|
||
}
|
||
|
||
const result = await response.json()
|
||
return result.url
|
||
} catch (error) {
|
||
console.error('Error uploading avatar:', error)
|
||
throw error
|
||
}
|
||
}
|
||
|
||
static getAvatarUrl(key: string): string {
|
||
return `${s3Config.endpoint}/${s3Config.bucket}/${key}`
|
||
}
|
||
|
||
static async deleteAvatar(key: string): Promise<void> {
|
||
try {
|
||
await fetch('/api/delete-avatar', {
|
||
method: 'DELETE',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ key }),
|
||
})
|
||
} catch (error) {
|
||
console.error('Error deleting avatar:', error)
|
||
throw error
|
||
}
|
||
}
|
||
}
|
||
|
||
export default S3Service
|