feat: port stroy-bot-main as the hub page

Project picker, section cards and the period Excel export now live on the
app's home page. The selected project is shared app state, so the sidebar
hides sections with the same rules main used to disable its cards
(archived, finished, no edit0 right).

Queries are 1:1 with stroy-bot-main and covered by tests against a fake
HTTP client. Behaviour differences are listed in the migration checklist.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Тимур Городецкий
2026-10-15 16:49:32 +05:00
parent b868e8012d
commit bed230f045
32 changed files with 1626 additions and 6 deletions
+40
View File
@@ -0,0 +1,40 @@
// Тексты главной — дословно из stroy-bot-main.
export const HUB_TEXTS = {
picker: {
label: 'Проект:',
placeholder: 'Выберите проект',
loading: 'Загрузка проектов…',
noProjects: 'Нет доступных проектов',
notFound: 'Проекты не найдены',
loadError: 'Ошибка загрузки. Попробуйте ещё раз.'
},
hint: 'Выберите проект, чтобы активировать ссылки ниже',
sectionsLabel: 'Разделы проекта',
exportLabel: 'Экспорт данных',
cards: {
objects: { title: 'Объекты', subtitle: 'Объекты по проекту' },
reports: { title: 'Отчёты по проекту', subtitle: 'Просмотр отчётности' },
report: { title: 'Отправить отчёт', subtitle: 'Отправка отчёта по проекту' },
import: { title: 'Загрузить работы из сметы', subtitle: 'Импорт работ в систему' },
archive: { title: 'Архив проекта', subtitle: 'Библиотека документов' },
resources: { title: 'Ресурсы проекта', subtitle: 'Профессии и компании' }
},
export: {
title: 'Выгрузить за период',
infoAriaLabel: 'Типы отчётов',
infoRows: [
{ label: 'Один день', text: '— ежедневный отчёт' },
{ label: 'Пн – Вс', text: '— еженедельный отчёт' },
{ label: 'Произвольный', text: '— отчёт за период' }
],
emptySubtitle: 'Укажите период для активации ссылки',
dateFrom: 'Начало',
dateTo: 'Конец',
button: 'Выгрузить',
buttonLoading: 'Формируется…',
invalidRange: 'Дата начала не может быть позже даты конца',
apiError: (status: number, statusText: string): string => `Ошибка API: ${status} ${statusText}`,
loadError: 'Ошибка при загрузке отчёта'
}
} as const;