diff --git a/corp.front/.dockerignore b/corp.front/.dockerignore
deleted file mode 100644
index 13e59b48..00000000
--- a/corp.front/.dockerignore
+++ /dev/null
@@ -1,35 +0,0 @@
-# Dependencies
-node_modules
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# Next.js
-.next/
-out/
-build
-dist
-
-# Environment
-.env*.local
-.env
-
-# Testing
-coverage
-
-# Misc
-.DS_Store
-*.pem
-
-# Debug
-*.log
-
-# IDE
-.vscode
-.idea
-*.swp
-*.swo
-*~
-
-# Vercel
-.vercel
diff --git a/corp.front/.env.example b/corp.front/.env.example
deleted file mode 100644
index f0f5164d..00000000
--- a/corp.front/.env.example
+++ /dev/null
@@ -1,5 +0,0 @@
-# Backend API URL
-NEXT_PUBLIC_API_URL=http://localhost:8000
-
-# WebSocket URL for real-time features
-NEXT_PUBLIC_WS_URL=ws://localhost:8000
diff --git a/corp.front/Dockerfile b/corp.front/Dockerfile
deleted file mode 100644
index 75ed2dd4..00000000
--- a/corp.front/Dockerfile
+++ /dev/null
@@ -1,48 +0,0 @@
-# Build stage
-FROM node:20-alpine AS builder
-
-WORKDIR /app
-
-# Copy package files
-COPY package.json package-lock.json* ./
-RUN npm ci
-
-# Copy source files
-COPY . .
-
-# Set environment variables for build
-ENV NEXT_TELEMETRY_DISABLED=1
-ENV NODE_ENV=production
-
-# Build the application
-RUN npm run build
-
-# Production stage
-FROM node:20-alpine AS runner
-
-WORKDIR /app
-
-ENV NODE_ENV=production
-ENV NEXT_TELEMETRY_DISABLED=1
-
-RUN addgroup --system --gid 1001 nodejs
-RUN adduser --system --uid 1001 nextjs
-
-# Copy necessary files from builder
-COPY --from=builder /app/public ./public
-COPY --from=builder /app/.next ./.next
-COPY --from=builder /app/node_modules ./node_modules
-COPY --from=builder /app/package.json ./package.json
-
-# Set correct permissions
-RUN chown -R nextjs:nodejs /app
-
-USER nextjs
-
-EXPOSE 3000
-
-ENV PORT=3000
-ENV HOSTNAME="0.0.0.0"
-
-# Start Next.js server
-CMD ["npm", "start"]
diff --git a/corp.front/INTEGRATION_GUIDE.md b/corp.front/INTEGRATION_GUIDE.md
deleted file mode 100644
index 31c6835d..00000000
--- a/corp.front/INTEGRATION_GUIDE.md
+++ /dev/null
@@ -1,410 +0,0 @@
-# Frontend Integration Guide
-
-## Обзор
-
-Фронтенд corp.front полностью интегрирован с Django Backend через REST API. Используется Next.js 16 с TypeScript и Tailwind CSS.
-
-## Структура проекта
-
-```
-corp.front/
-├── src/
-│ ├── app/ # Next.js страницы
-│ │ ├── page.tsx # Главная (Лента) ✅ Интегрирован
-│ │ ├── employees/ # Сотрудники ✅ Интегрирован
-│ │ ├── departments/ # Отделы
-│ │ ├── documents/ # Документы
-│ │ ├── messages/ # Сообщения
-│ │ ├── requests/ # Заявки
-│ │ ├── finances/ # Финансы
-│ │ └── login/ # Вход
-│ ├── lib/
-│ │ └── api.ts # API клиент ✅
-│ ├── types/
-│ │ └── api.ts # TypeScript типы ✅
-│ └── hooks/
-│ └── useApi.ts # React хуки для API ✅
-```
-
-## API клиент
-
-### Базовая конфигурация
-
-API клиент автоматически:
-- Добавляет JWT токен к запросам
-- Обрабатывает ошибки авторизации
-- Сохраняет токены в localStorage
-- Перенаправляет на /login при 401
-
-### Использование
-
-```typescript
-import apiClient from '@/lib/api';
-
-// Авторизация
-const { access, refresh, user } = await apiClient.login({
- username: 'user@example.com',
- password: 'password'
-});
-
-// Получение данных
-const employees = await apiClient.getEmployees();
-const posts = await apiClient.getPosts();
-```
-
-## React хуки
-
-Используйте готовые хуки из `@/hooks/useApi`:
-
-```tsx
-import { useCurrentUser, useEmployees, usePosts } from '@/hooks/useApi';
-
-function MyComponent() {
- const { user, loading, error } = useCurrentUser();
- const { employees } = useEmployees({ search: 'John' });
- const { posts } = usePosts({ page: 1 });
-
- if (loading) return
Загрузка...
;
- if (error) return Ошибка: {error.message}
;
-
- return {/* UI */}
;
-}
-```
-
-### Доступные хуки
-
-- `useCurrentUser()` - текущий пользователь
-- `useEmployees(params?)` - список сотрудников
-- `useDepartments()` - список отделов
-- `usePosts(params?)` - посты ленты
-- `useDocuments(params?)` - документы
-- `useRequests(params?)` - заявки
-- `useChats()` - чаты
-- `useNotifications()` - уведомления
-
-## TypeScript типы
-
-Все типы данных определены в `@/types/api.ts`:
-
-```typescript
-import type { User, Post, Department, Document } from '@/types/api';
-```
-
-## Интегрированные страницы
-
-### ✅ Главная страница (Лента)
-
-**Файл**: `src/app/page.tsx`
-
-**Функции**:
-- Загрузка постов из API
-- Отображение автора, времени, контента
-- Лайки и комментарии
-- Теги постов
-
-**Используемые хуки**:
-- `usePosts()` - получение постов
-- `useCurrentUser()` - текущий пользователь
-
-### ✅ Сотрудники
-
-**Файл**: `src/app/employees/page.tsx`
-
-**Функции**:
-- Список всех сотрудников
-- Поиск по имени
-- Статус (онлайн/оффлайн)
-- Должность и отдел
-
-**Используемые хуки**:
-- `useEmployees({ search })` - поиск сотрудников
-- `useCurrentUser()` - текущий пользователь
-
-## Переменные окружения
-
-### Для локальной разработки
-
-`.env.local`:
-```env
-NEXT_PUBLIC_API_URL=http://localhost:8000
-NEXT_PUBLIC_WS_URL=ws://localhost:8000
-```
-
-### Для Docker
-
-`.env.local` (автоматически используется в docker-compose):
-```env
-NEXT_PUBLIC_API_URL=http://web:8000
-NEXT_PUBLIC_WS_URL=ws://web:8000
-```
-
-## Запуск
-
-### Локальная разработка
-
-```bash
-cd corp.front
-npm install
-npm run dev
-```
-
-Доступно на: http://localhost:3000
-
-### Docker
-
-```bash
-# Из корня проекта
-docker-compose up -d frontend
-```
-
-Доступно через nginx: http://localhost
-
-## Интеграция новых страниц
-
-### Шаг 1: Создать страницу
-
-```tsx
-// src/app/mypage/page.tsx
-"use client";
-
-import { useMyData } from '@/hooks/useApi';
-
-export default function MyPage() {
- const { data, loading, error } = useMyData();
-
- if (loading) return Загрузка...
;
- if (error) return Ошибка: {error.message}
;
-
- return (
-
- {data.map(item => (
-
{item.name}
- ))}
-
- );
-}
-```
-
-### Шаг 2: Добавить метод в API клиент
-
-```typescript
-// src/lib/api.ts
-class ApiClient {
- // ... existing methods
-
- async getMyData() {
- return this.request('/mydata/');
- }
-}
-```
-
-### Шаг 3: Создать хук (опционально)
-
-```typescript
-// src/hooks/useApi.ts
-export function useMyData() {
- const [data, setData] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- async function fetchData() {
- try {
- const result = await apiClient.getMyData();
- setData(result);
- } catch (err) {
- setError(err);
- } finally {
- setLoading(false);
- }
- }
- fetchData();
- }, []);
-
- return { data, loading, error };
-}
-```
-
-## API Endpoints
-
-Полный список доступных эндпоинтов:
-
-### Auth
-- `POST /api/auth/token/` - Login
-- `POST /api/auth/token/refresh/` - Refresh token
-- `POST /api/v1/auth/register/` - Регистрация
-
-### Employees
-- `GET /api/v1/employees/` - Список сотрудников
-- `GET /api/v1/employees/{id}/` - Детали сотрудника
-- `GET /api/v1/employees/me/` - Текущий пользователь
-
-### Departments
-- `GET /api/v1/departments/` - Список отделов
-- `GET /api/v1/departments/{id}/` - Детали отдела
-
-### Feed
-- `GET /api/v1/posts/` - Посты ленты
-- `POST /api/v1/posts/` - Создать пост
-- `POST /api/v1/posts/{id}/like/` - Лайк поста
-- `GET /api/v1/comments/` - Комментарии
-- `POST /api/v1/comments/` - Создать комментарий
-
-### Documents
-- `GET /api/v1/documents/` - Документы
-- `GET /api/v1/documents/{id}/` - Детали документа
-
-### Requests
-- `GET /api/v1/requests/` - Заявки
-- `POST /api/v1/requests/` - Создать заявку
-- `GET /api/v1/requests/{id}/` - Детали заявки
-
-### Communications
-- `GET /api/v1/communications/chats/` - Чаты
-- `GET /api/v1/communications/messages/` - Сообщения
-- `POST /api/v1/communications/messages/` - Отправить сообщение
-
-### Calendar
-- `GET /api/v1/calendar/events/` - События календаря
-- `GET /api/v1/calendar/calendars/` - Календари
-
-### Notifications
-- `GET /api/v1/notifications/` - Уведомления
-- `POST /api/v1/notifications/{id}/mark_read/` - Отметить прочитанным
-- `POST /api/v1/notifications/mark_all_read/` - Отметить все прочитанными
-
-## Аутентификация
-
-### Вход
-
-```typescript
-import apiClient from '@/lib/api';
-
-async function handleLogin(username: string, password: string) {
- try {
- const { access, refresh, user } = await apiClient.login({
- username,
- password
- });
-
- // Токен автоматически сохранён
- // Перенаправить пользователя
- router.push('/');
- } catch (error) {
- console.error('Login failed:', error);
- }
-}
-```
-
-### Выход
-
-```typescript
-import apiClient from '@/lib/api';
-
-function handleLogout() {
- apiClient.clearToken();
- router.push('/login');
-}
-```
-
-### Защищённые страницы
-
-```tsx
-"use client";
-
-import { useEffect } from 'react';
-import { useRouter } from 'next/navigation';
-import apiClient from '@/lib/api';
-
-export default function ProtectedPage() {
- const router = useRouter();
-
- useEffect(() => {
- const token = apiClient.getToken();
- if (!token) {
- router.push('/login');
- }
- }, []);
-
- return Protected content
;
-}
-```
-
-## Обработка ошибок
-
-API клиент автоматически обрабатывает:
-
-- **401 Unauthorized**: Очищает токены и перенаправляет на `/login`
-- **Network errors**: Выбрасывает исключение с сообщением
-
-Пример обработки в компонентах:
-
-```tsx
-const { data, loading, error } = useMyData();
-
-if (loading) return ;
-
-if (error) {
- return (
-
-
Ошибка загрузки данных
-
{error.message}
-
-
- );
-}
-```
-
-## WebSocket (для будущей реализации)
-
-Для real-time обновлений можно добавить WebSocket соединение:
-
-```typescript
-const WS_URL = process.env.NEXT_PUBLIC_WS_URL || 'ws://localhost:8000';
-
-const socket = new WebSocket(`${WS_URL}/ws/notifications/`);
-
-socket.onmessage = (event) => {
- const data = JSON.parse(event.data);
- // Обработать уведомление
-};
-```
-
-## Рекомендации
-
-1. **Всегда используйте хуки** для получения данных из API
-2. **Обрабатывайте loading и error** состояния в UI
-3. **Используйte TypeScript типы** для type-safety
-4. **Не сохраняйте чувствительные данные** в localStorage кроме токенов
-5. **Валидируйте данные** перед отправкой на сервер
-
-## Troubleshooting
-
-###CORS ошибки
-
-Убедитесь, что backend настроен с правильными CORS заголовками:
-
-```python
-# backend/eusrr_backend/settings.py
-CORS_ALLOWED_ORIGINS = [
- "http://localhost:3000",
- "http://localhost",
-]
-```
-
-### 401 Unauthorized
-
-- Проверьте, что токен действителен
-- Убедитесь, что backend запущен
-- Проверьте переменные окружения
-
-### Ошибка сети
-
-- Проверьте, что backend доступен
-- Проверьте URL в `NEXT_PUBLIC_API_URL`
-- Проверьте docker network, если используете docker-compose
-
----
-
-**Дата создания**: 19 февраля 2026
-**Версия**: 1.0
diff --git a/corp.front/next.config.ts b/corp.front/next.config.ts
deleted file mode 100644
index 1d2435c6..00000000
--- a/corp.front/next.config.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import type { NextConfig } from "next";
-
-const nextConfig: NextConfig = {
- // Rewrites не нужны - в production используйте nginx (http://localhost)
- // Для dev можно запустить backend локально на localhost:8000
-
- // Environment variables
- env: {
- NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
- NEXT_PUBLIC_WS_URL: process.env.NEXT_PUBLIC_WS_URL,
- },
-};
-
-export default nextConfig;
diff --git a/corp.front/src/app/employees/page.tsx b/corp.front/src/app/employees/page.tsx
deleted file mode 100644
index be6aacfc..00000000
--- a/corp.front/src/app/employees/page.tsx
+++ /dev/null
@@ -1,220 +0,0 @@
-"use client";
-
-import { Bell, Building2, FileSignature, FileText, Home as HomeIcon, MessageSquare, Search, Users, Wallet } from "lucide-react";
-import Link from "next/link";
-import { usePathname, useRouter } from "next/navigation";
-import { useEmployees, useCurrentUser } from "@/hooks/useApi";
-import { useState, useEffect } from "react";
-import { apiClient } from "@/lib/api";
-
-const weekdays = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"];
-
-const calendarWeeks = [
- ["", "", "", "", "1", "2", "3"],
- ["4", "5", "6", "7", "8", "9", "10"],
- ["11", "12", "13", "14", "15", "16", "17"],
- ["18", "19", "20", "21", "22", "23", "24"],
- ["25", "26", "27", "28", "", "", ""],
-];
-
-export default function EmployeesPage() {
- const pathname = usePathname();
- const router = useRouter();
- const [searchQuery, setSearchQuery] = useState("");
- const { employees, loading, error } = useEmployees({ search: searchQuery });
- const { user } = useCurrentUser();
-
- // Проверка авторизации
- useEffect(() => {
- const token = apiClient.getToken();
- if (!token) {
- router.push('/login');
- }
- }, [router]);
-
- const sortedEmployees = employees.sort((a, b) =>
- `${a.first_name} ${a.last_name}`.localeCompare(`${b.first_name} ${b.last_name}`, "ru")
- );
-
- const navLinkClass = (href: string) =>
- `flex items-center gap-3 rounded-lg px-3 py-2 hover:bg-gray-50 ${pathname === href ? "bg-sky-50 text-sky-700 ring-1 ring-sky-100" : "text-gray-700"
- }`;
-
- const navIconClass = (href: string) => (pathname === href ? "text-sky-700" : "text-gray-400");
-
- return (
-
-
-
-
-

-
-
-
-
- setSearchQuery(e.target.value)}
- className="w-full rounded-full border border-gray-200 bg-gray-50 py-2.5 pl-11 pr-4 text-sm text-gray-800 transition focus:border-sky-500 focus:bg-white focus:outline-none focus:ring-2 focus:ring-sky-100"
- placeholder="Поиск сотрудников..."
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Всего: {employees.length}
-
-
-
-
- {loading && (
-
-
Загрузка сотрудников...
-
- )}
- {error && (
-
-
Ошибка загрузки: {error.message}
-
- )}
- {!loading && !error && employees.length === 0 && (
-
-
Сотрудники не найдены
-
- )}
- {!loading && sortedEmployees.map((employee) => {
- const isOnline = employee.is_active;
- const statusText = isOnline ? "Онлайн" : "Оффлайн";
- const statusColor = isOnline ? "text-green-600" : "text-gray-500";
- const dotColor = isOnline ? "bg-green-500" : "bg-gray-400";
- const fullName = `${employee.first_name} ${employee.last_name}`;
-
- return (
-
-
- {employee.first_name[0]}{employee.last_name[0]}
-
-
-
{fullName}
-
{employee.position?.name || 'Не указана'}
-
-
- {statusText}
- {employee.department && (
- <>
- •
- {employee.department.name}
- >
- )}
-
-
-
- );
- })}
-
-
-
-
-
-
- );
-}
diff --git a/corp.front/src/app/login/page.tsx b/corp.front/src/app/login/page.tsx
deleted file mode 100644
index 69387fa2..00000000
--- a/corp.front/src/app/login/page.tsx
+++ /dev/null
@@ -1,111 +0,0 @@
-'use client';
-
-import { useState, FormEvent } from 'react';
-import { useRouter } from 'next/navigation';
-import { apiClient } from '@/lib/api';
-
-export default function Login() {
- const [email, setEmail] = useState('');
- const [password, setPassword] = useState('');
- const [error, setError] = useState('');
- const [loading, setLoading] = useState(false);
- const router = useRouter();
-
- const handleSubmit = async (e: FormEvent) => {
- e.preventDefault();
- setError('');
- setLoading(true);
-
- try {
- const response = await apiClient.login({ email, password });
- console.log('Успешная авторизация:', response.user);
-
- // Перенаправляем на главную страницу
- router.push('/');
- router.refresh(); // Обновляем данные
- } catch (err) {
- console.error('Ошибка авторизации:', err);
- setError('Неверный email или пароль');
- } finally {
- setLoading(false);
- }
- };
-
- return (
-
-
-
-
- Войти в систему EUSRR
-
-
- Используйте учетные данные LDAP для входа
-
-
-
-
-
-
-
- Для входа используйте корпоративные учетные данные
-
-
-
-
- );
-}
diff --git a/corp.front/src/app/page.tsx b/corp.front/src/app/page.tsx
deleted file mode 100644
index b6401d00..00000000
--- a/corp.front/src/app/page.tsx
+++ /dev/null
@@ -1,257 +0,0 @@
-"use client";
-
-import { Bell, Bookmark, Building2, FileSignature, FileText, Heart, HeartHandshake, Home as HomeIcon, MessageSquare, Search, Star, Users, Wallet } from "lucide-react";
-import Link from "next/link";
-import { usePathname, useRouter } from "next/navigation";
-import { usePosts, useCurrentUser } from "@/hooks/useApi";
-import { useEffect } from "react";
-import { apiClient } from "@/lib/api";
-
-function formatTimeAgo(dateString: string): string {
- const date = new Date(dateString);
- const now = new Date();
- const diffInMs = now.getTime() - date.getTime();
- const diffInMinutes = Math.floor(diffInMs / (1000 * 60));
- const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60));
- const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
-
- if (diffInMinutes < 60) return `${diffInMinutes} минут назад`;
- if (diffInHours < 24) return `${diffInHours} часов назад`;
- return `${diffInDays} дней назад`;
-}
-
-const weekdays = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"];
-
-const calendarWeeks = [
- ["", "", "", "", "1", "2", "3"],
- ["4", "5", "6", "7", "8", "9", "10"],
- ["11", "12", "13", "14", "15", "16", "17"],
- ["18", "19", "20", "21", "22", "23", "24"],
- ["25", "26", "27", "28", "", "", ""],
-];
-
-export default function Home() {
- const pathname = usePathname();
- const router = useRouter();
- const { posts, loading, error } = usePosts();
- const { user } = useCurrentUser();
-
- // Проверка авторизации при загрузке
- useEffect(() => {
- const token = apiClient.getToken();
- if (!token) {
- router.push('/login');
- }
- }, [router]);
-
- const navLinkClass = (href: string) =>
- `flex items-center gap-3 rounded-lg px-3 py-2 hover:bg-gray-50 ${pathname === href ? "bg-sky-50 text-sky-700 ring-1 ring-sky-100" : "text-gray-700"
- }`;
-
- const navIconClass = (href: string) => (pathname === href ? "text-sky-700" : "text-gray-400");
-
- return (
-
-
-
-
-

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Статья
- Фото
- Ссылка
- Опрос
- Событие
-
-
-
-
- {loading && (
-
- )}
- {error && (
-
-
Ошибка загрузки: {error.message}
-
Проверьте подключение к серверу
-
- )}
- {!loading && !error && posts.length === 0 && (
-
- )}
- {!loading && posts.map((post) => (
-
-
- {post.content}
- {post.tags && post.tags.length > 0 && (
-
- {post.tags.map((tag) => (
-
- #{tag}
-
- ))}
-
- )}
-
-
-
-
-
-
- ))}
-
-
-
-
-
-
- );
-}
diff --git a/corp.front/src/app/register/page.tsx b/corp.front/src/app/register/page.tsx
deleted file mode 100644
index 3e46b971..00000000
--- a/corp.front/src/app/register/page.tsx
+++ /dev/null
@@ -1,262 +0,0 @@
-'use client';
-
-import { useState, FormEvent } from 'react';
-import { useRouter } from 'next/navigation';
-import { apiClient } from '@/lib/api';
-import Link from "next/link";
-
-export default function Register() {
- const [formData, setFormData] = useState({
- first_name: '',
- last_name: '',
- middle_name: '',
- email: '',
- phone_number: '',
- telegram: '',
- password: '',
- confirmPassword: '',
- });
- const [error, setError] = useState('');
- const [loading, setLoading] = useState(false);
- const router = useRouter();
-
- const handleChange = (e: React.ChangeEvent) => {
- setFormData({
- ...formData,
- [e.target.name]: e.target.value,
- });
- };
-
- const handleSubmit = async (e: FormEvent) => {
- e.preventDefault();
- setError('');
-
- // Валидация
- if (formData.password !== formData.confirmPassword) {
- setError('Пароли не совпадают');
- return;
- }
-
- if (!formData.email && !formData.phone_number && !formData.telegram) {
- setError('Укажите хотя бы один способ связи: email, телефон или Telegram');
- return;
- }
-
- setLoading(true);
-
- try {
- const registerData = {
- email: formData.email,
- phone_number: formData.phone_number,
- password: formData.password,
- first_name: formData.first_name,
- last_name: formData.last_name,
- middle_name: formData.middle_name || undefined,
- telegram: formData.telegram || undefined,
- };
-
- await apiClient.register(registerData);
-
- // После успешной регистрации авторизуемся
- const loginData = {
- email: formData.email,
- phone_number: formData.phone_number,
- password: formData.password
- };
- await apiClient.login(loginData);
-
- router.push('/');
- } catch (err: any) {
- console.error('Ошибка регистрации:', err);
- setError(err.message || 'Ошибка при регистрации. Проверьте введенные данные.');
- } finally {
- setLoading(false);
- }
- };
-
- return (
-
-
-
-
- Регистрация
-
-
- Создайте новый аккаунт, указав имя и контактные данные.
-
-
-
-
-
-
- Уже есть аккаунт? Войти
-
-
-
-
- Регистрируясь, вы принимаете условия использования и подтверждаете ознакомление с политикой конфиденциальности.
-
-
-
-
- );
-}
diff --git a/corp.front/src/hooks/useApi.ts b/corp.front/src/hooks/useApi.ts
deleted file mode 100644
index 7e814b56..00000000
--- a/corp.front/src/hooks/useApi.ts
+++ /dev/null
@@ -1,218 +0,0 @@
-"use client";
-
-import { useEffect, useState } from 'react';
-import apiClient from '@/lib/api';
-import type { User, Post, PaginatedResponse } from '@/types/api';
-
-export function useCurrentUser() {
- const [user, setUser] = useState(null);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- async function fetchUser() {
- try {
- const data = await apiClient.getCurrentUser();
- setUser(data);
- } catch (err) {
- setError(err as Error);
- } finally {
- setLoading(false);
- }
- }
-
- fetchUser();
- }, []);
-
- return { user, loading, error };
-}
-
-export function useEmployees(params?: { search?: string; department?: string }) {
- const [employees, setEmployees] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- async function fetchEmployees() {
- try {
- setLoading(true);
- const data = await apiClient.getEmployees(params);
- setEmployees(data.results || data);
- } catch (err) {
- setError(err as Error);
- } finally {
- setLoading(false);
- }
- }
-
- fetchEmployees();
- }, [params?.search, params?.department]);
-
- return { employees, loading, error, refetch: () => { } };
-}
-
-export function useDepartments() {
- const [departments, setDepartments] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- async function fetchDepartments() {
- try {
- const data = await apiClient.getDepartments();
- setDepartments(data.results || data);
- } catch (err) {
- setError(err as Error);
- } finally {
- setLoading(false);
- }
- }
-
- fetchDepartments();
- }, []);
-
- return { departments, loading, error };
-}
-
-export function usePosts(params?: { page?: number; search?: string }) {
- const [posts, setPosts] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
- const [hasMore, setHasMore] = useState(false);
-
- useEffect(() => {
- async function fetchPosts() {
- try {
- setLoading(true);
- const data: PaginatedResponse = await apiClient.getPosts(params);
- setPosts(data.results);
- setHasMore(!!data.next);
- } catch (err) {
- setError(err as Error);
- } finally {
- setLoading(false);
- }
- }
-
- fetchPosts();
- }, [params?.page, params?.search]);
-
- return { posts, loading, error, hasMore, refetch: () => { } };
-}
-
-export function useDocuments(params?: { search?: string; type?: string }) {
- const [documents, setDocuments] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- async function fetchDocuments() {
- try {
- const data = await apiClient.getDocuments(params);
- setDocuments(data.results || data);
- } catch (err) {
- setError(err as Error);
- } finally {
- setLoading(false);
- }
- }
-
- fetchDocuments();
- }, [params?.search, params?.type]);
-
- return { documents, loading, error };
-}
-
-export function useRequests(params?: { status?: string; type?: string }) {
- const [requests, setRequests] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- async function fetchRequests() {
- try {
- const data = await apiClient.getRequests(params);
- setRequests(data.results || data);
- } catch (err) {
- setError(err as Error);
- } finally {
- setLoading(false);
- }
- }
-
- fetchRequests();
- }, [params?.status, params?.type]);
-
- return { requests, loading, error };
-}
-
-export function useChats() {
- const [chats, setChats] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- async function fetchChats() {
- try {
- const data = await apiClient.getChats();
- setChats(data.results || data);
- } catch (err) {
- setError(err as Error);
- } finally {
- setLoading(false);
- }
- }
-
- fetchChats();
- }, []);
-
- return { chats, loading, error };
-}
-
-export function useNotifications() {
- const [notifications, setNotifications] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
- const [unreadCount, setUnreadCount] = useState(0);
-
- useEffect(() => {
- async function fetchNotifications() {
- try {
- const data = await apiClient.getNotifications();
- const notifs = data.results || data;
- setNotifications(notifs);
- setUnreadCount(notifs.filter((n: any) => !n.is_read).length);
- } catch (err) {
- setError(err as Error);
- } finally {
- setLoading(false);
- }
- }
-
- fetchNotifications();
- }, []);
-
- const markAsRead = async (id: number) => {
- try {
- await apiClient.markNotificationAsRead(id);
- setNotifications(prev =>
- prev.map(n => (n.id === id ? { ...n, is_read: true } : n))
- );
- setUnreadCount(prev => Math.max(0, prev - 1));
- } catch (err) {
- console.error('Failed to mark notification as read:', err);
- }
- };
-
- const markAllAsRead = async () => {
- try {
- await apiClient.markAllNotificationsAsRead();
- setNotifications(prev => prev.map(n => ({ ...n, is_read: true })));
- setUnreadCount(0);
- } catch (err) {
- console.error('Failed to mark all notifications as read:', err);
- }
- };
-
- return { notifications, loading, error, unreadCount, markAsRead, markAllAsRead };
-}
diff --git a/corp.front/src/types/api.ts b/corp.front/src/types/api.ts
deleted file mode 100644
index e1acd0a4..00000000
--- a/corp.front/src/types/api.ts
+++ /dev/null
@@ -1,164 +0,0 @@
-// Common types
-export interface User {
- id: number;
- email: string;
- phone_number?: string;
- first_name: string;
- last_name: string;
- middle_name?: string;
- position?: Position;
- department?: Department;
- avatar?: string;
- is_active: boolean;
- telegram?: string;
-}
-
-export interface Department {
- id: number;
- name: string;
- description?: string;
- parent?: number;
- head?: User;
- employees_count?: number;
-}
-
-export interface Position {
- id: number;
- name: string;
- description?: string;
-}
-
-// Feed types
-export interface Post {
- id: number;
- author: User;
- content: string;
- tags?: string[];
- created_at: string;
- updated_at: string;
- likes_count: number;
- comments_count: number;
- is_liked?: boolean;
-}
-
-export interface Comment {
- id: number;
- post: number;
- author: User;
- content: string;
- created_at: string;
- updated_at: string;
-}
-
-// Documents types
-export interface Document {
- id: number;
- title: string;
- description?: string;
- file?: string;
- document_type: string;
- created_by: User;
- created_at: string;
- updated_at: string;
- tags?: string[];
-}
-
-// Requests types
-export interface Request {
- id: number;
- title: string;
- description: string;
- request_type: string;
- status: 'pending' | 'approved' | 'rejected' | 'in_progress' | 'completed';
- created_by: User;
- assigned_to?: User;
- created_at: string;
- updated_at: string;
-}
-
-// Communications types
-export interface Chat {
- id: number;
- name?: string;
- chat_type: 'direct' | 'group' | 'department';
- participants: User[];
- last_message?: Message;
- unread_count?: number;
- created_at: string;
-}
-
-export interface Message {
- id: number;
- chat: number;
- sender: User;
- content: string;
- is_read: boolean;
- created_at: string;
-}
-
-// Calendar types
-export interface CalendarEvent {
- id: number;
- title: string;
- description?: string;
- start_time: string;
- end_time: string;
- location?: string;
- calendar: number;
- participants?: User[];
- created_by: User;
-}
-
-export interface Calendar {
- id: number;
- name: string;
- description?: string;
- color?: string;
- is_public: boolean;
- owner: User;
-}
-
-// Notifications types
-export interface Notification {
- id: number;
- title: string;
- message: string;
- notification_type: string;
- is_read: boolean;
- created_at: string;
- link?: string;
-}
-
-// API Response types
-export interface PaginatedResponse {
- count: number;
- next: string | null;
- previous: string | null;
- results: T[];
-}
-
-// Auth types
-export interface LoginCredentials {
- email?: string;
- phone?: string;
- phone_number?: string;
- password: string;
-}
-
-export interface LoginResponse {
- access: string;
- refresh: string;
- user: User;
-}
-
-export interface RegisterData {
- email: string;
- phone_number: string;
- password: string;
- first_name: string;
- last_name: string;
- middle_name?: string;
- telegram?: string;
- whatsapp?: string;
- wechat?: string;
-}
diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx
index c7ee372c..50ab629b 100644
--- a/frontend/src/app/layout.tsx
+++ b/frontend/src/app/layout.tsx
@@ -14,8 +14,8 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "EUSRR - Корпоративная система",
+ description: "Корпоративная система управления EUSRR",
};
export default function RootLayout({