UI: секретный вход в админку — удержание кнопки меню 10с; убраны видимые кнопки входа админа

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 16:40:49 +03:00
co-authored by Claude Opus 4.8
parent 460b57e792
commit d32237975d
3 changed files with 33 additions and 17 deletions
+33 -1
View File
@@ -1,9 +1,12 @@
import { Menu, Plus, Users } from "lucide-react"; import { Menu, Plus, Users } from "lucide-react";
import { useRef } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useToast } from "../context/ToastContext"; import { useToast } from "../context/ToastContext";
import { useMe } from "../hooks/auth"; import { useMe } from "../hooks/auth";
const ADMIN_HOLD_MS = 10000; // секретный вход в админку — удержание кнопки меню 10с
export function BottomBar({ onMenu }: { onMenu: () => void }) { export function BottomBar({ onMenu }: { onMenu: () => void }) {
const { data: me } = useMe(); const { data: me } = useMe();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -11,6 +14,28 @@ export function BottomBar({ onMenu }: { onMenu: () => void }) {
const hasGroup = me?.active_group_id != null; const hasGroup = me?.active_group_id != null;
const activeGroup = me?.groups.find((g) => g.id === me?.active_group_id); const activeGroup = me?.groups.find((g) => g.id === me?.active_group_id);
// Долгое удержание кнопки меню → /admin/login; короткий тап → открыть боковое меню.
const holdTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
const holdFired = useRef(false);
const startHold = () => {
holdFired.current = false;
holdTimer.current = setTimeout(() => {
holdFired.current = true;
navigate("/admin/login");
}, ADMIN_HOLD_MS);
};
const clearHold = () => {
if (holdTimer.current) {
clearTimeout(holdTimer.current);
holdTimer.current = null;
}
};
const endHold = () => {
clearHold();
if (!holdFired.current) onMenu(); // обычный тап
};
const onCreate = () => { const onCreate = () => {
if (!hasGroup) { if (!hasGroup) {
toast.show("Вы не состоите в группе. Создайте или вступите в группу."); toast.show("Вы не состоите в группе. Создайте или вступите в группу.");
@@ -29,7 +54,14 @@ export function BottomBar({ onMenu }: { onMenu: () => void }) {
<div className="spacer" /> <div className="spacer" />
<button className="slot" onClick={onMenu} aria-label="Меню"> <button
className="slot"
aria-label="Меню"
onPointerDown={startHold}
onPointerUp={endHold}
onPointerLeave={clearHold}
onPointerCancel={clearHold}
>
<Menu size={20} /> <Menu size={20} />
<span>Меню</span> <span>Меню</span>
</button> </button>
-6
View File
@@ -158,12 +158,6 @@ export function AccountPage() {
<button className="btn btn-danger" style={{ width: "100%" }} onClick={doLogout}> <button className="btn btn-danger" style={{ width: "100%" }} onClick={doLogout}>
Выйти Выйти
</button> </button>
<p className="center" style={{ marginTop: 24 }}>
<button className="btn btn-ghost small muted" onClick={() => navigate("/admin/login")}>
Вход для администратора
</button>
</p>
</div> </div>
); );
} }
-10
View File
@@ -93,16 +93,6 @@ export function LoginPage() {
{showStub && !pendingTg && <DevLogin onError={setError} />} {showStub && !pendingTg && <DevLogin onError={setError} />}
{error && <p className="error-text center">{error}</p>} {error && <p className="error-text center">{error}</p>}
<p className="center" style={{ marginTop: 40 }}>
<button
className="btn btn-ghost small"
onClick={() => navigate("/admin/login")}
style={{ opacity: 0.4 }}
>
·
</button>
</p>
</div> </div>
</div> </div>
); );