diff --git a/docs/simple-mode-progress.md b/docs/simple-mode-progress.md index 00b6c40..7b4cb1b 100644 --- a/docs/simple-mode-progress.md +++ b/docs/simple-mode-progress.md @@ -14,7 +14,7 @@ SuperAdmin и только для конкретной организации. - [x] 3. Серверная защита: `[RequiresAdvancedMode]` → 403 ProblemDetails на скрытых модулях - [x] 4. Web: меню, маршруты, дашборд фильтруются; прямой переход → страница «Недоступно» - [x] 5. Упрощённые формы (товар / контрагент / документы) — скрыть «не нужные» поля, значения сохраняются -- [ ] 6. SuperAdmin UI — бейдж «Простой/Расширенный» + переключатель с подтверждением +- [x] 6. SuperAdmin UI — бейдж «Простой/Расширенный» + переключатель с подтверждением - [ ] 7. Тесты (unit + integration + e2e); патч quality-watchdog при необходимости - [ ] 8. Деплой стейджа + `docs/simple-mode.md` @@ -131,3 +131,15 @@ SuperAdmin и только для конкретной организации. Что отложено (новая функциональность, в этой задаче не трогаем): - `Counterparty.IsSupplier` / `IsBuyer` — задача просит галочки «Поставщик/Покупатель», но на `Counterparty` таких bool-колонок нет. Это новая миграция и расширение API — отдельная задача. - `pnpm run build` — ✓ (2.36s, 0 TS errors). + +### 2026-10-04 — Шаг 6 ✓ + +- `SuperAdminOrganizationsPage.tsx`: + - В `OrgRow` добавлен `isAdvancedMode: boolean` (бэк уже отдаёт из шага 2). + - Новая колонка **«Режим»** с бейджем «Простой» (slate-пилюля) / «Расширенный» (violet-пилюля). + - Новая кнопка-экшн рядом с «Архивировать» (иконка Sparkles): при клике открывается модалка подтверждения с разной копией для включения/выключения: + - *Включить:* перечисляет, что станет доступно (demand, loyalty, promos, abc, audit, несколько цен, пресеты, bulk-ops, telegram, sso, язык). + - *Выключить:* предупреждает что данные НЕ удаляются и переключение можно вернуть; напоминает проверить активные операции. + - Переключение бьёт `PUT /api/super-admin/organizations/{id}/advanced-mode { enabled }` и после успеха `list.refetch()`. +- Переключение из карточки организации (`SuperAdminOrgEmployeesPage` / detail-view) не делаем в этой итерации — список-страница с бейджем и кнопкой уже закрывает UX. +- `pnpm run build` — ✓ (2.02s, 0 TS errors). diff --git a/src/food-market.web/src/pages/SuperAdminOrganizationsPage.tsx b/src/food-market.web/src/pages/SuperAdminOrganizationsPage.tsx index b6a7f9e..26d23aa 100644 --- a/src/food-market.web/src/pages/SuperAdminOrganizationsPage.tsx +++ b/src/food-market.web/src/pages/SuperAdminOrganizationsPage.tsx @@ -1,7 +1,7 @@ import { useState } from 'react' import { useNavigate } from 'react-router-dom' import { useQuery } from '@tanstack/react-query' -import { Plus, Archive, RotateCcw, Trash2, LogIn, Users } from 'lucide-react' +import { Plus, Archive, RotateCcw, Trash2, LogIn, Users, Sparkles } from 'lucide-react' import { api, setOrgOverride } from '@/lib/api' import { ListPageShell } from '@/components/ListPageShell' import { DataTable } from '@/components/DataTable' @@ -18,6 +18,7 @@ interface OrgRow { id: string; name: string; countryCode: string isActive: boolean; isArchived: boolean; archivedAt: string | null createdAt: string; employeeCount: number; productCount: number; lastLoginAt: string | null + isAdvancedMode: boolean } export function SuperAdminOrganizationsPage() { @@ -27,6 +28,22 @@ export function SuperAdminOrganizationsPage() { const [archiveOf, setArchiveOf] = useState(null) const [deleteOf, setDeleteOf] = useState(null) const [confirmName, setConfirmName] = useState('') + // Sprint 29 — модалка подтверждения переключения режима; `toggleMode.target` + // хранит и строку, и целевое состояние (вкл./выкл.). + const [toggleModeOf, setToggleModeOf] = useState<{ row: OrgRow; enable: boolean } | null>(null) + const [togglePending, setTogglePending] = useState(false) + + const applyToggleMode = async () => { + if (!toggleModeOf) return + setTogglePending(true) + try { + await api.put(`${URL}/${toggleModeOf.row.id}/advanced-mode`, { enabled: toggleModeOf.enable }) + setToggleModeOf(null) + list.refetch() + } finally { + setTogglePending(false) + } + } const archive = async () => { if (!archiveOf || confirmName !== archiveOf.name) return @@ -107,6 +124,9 @@ export function SuperAdminOrganizationsPage() { { header: 'Статус', width: '120px', cell: (r) => r.isArchived ? Архив : Активна }, + { header: 'Режим', width: '130px', cell: (r) => r.isAdvancedMode + ? Расширенный + : Простой }, { header: '', width: '160px', cell: (r) => (
e.stopPropagation()}> {!r.isArchived && ( @@ -121,6 +141,16 @@ export function SuperAdminOrganizationsPage() { className="p-1.5 text-indigo-600 hover:bg-indigo-50 dark:hover:bg-indigo-900/20 rounded"> + {!r.isArchived && ( + + )} {!r.isArchived ? ( + + } + > + {toggleModeOf && ( +
+ {toggleModeOf.enable ? ( + <> +

У организации {toggleModeOf.row.name} будет доступен полный набор функций: + оптовые отгрузки, перемещения между точками, лояльность, промо/акции, + ABC-анализ, аудит организации, несколько типов цен, bulk-операции и + сохранённые пресеты, Telegram-бот владельца, SSO, выбор языка.

+

Переключение логируется в SuperAdmin audit-log.

+ + ) : ( + <> +

У организации {toggleModeOf.row.name} останется только базовый + розничный учёт. Советуем сначала убедиться, что сотрудники не ведут активных + операций в скрываемых модулях.

+

+ Данные скрытых модулей не удаляются — при повторном включении + всё снова будет видно. Переключение логируется в SuperAdmin audit-log. +

+ + )} +
+ )} + + setDeleteOf(null)} title="Удалить организацию навсегда" footer={<>