feat: enhance Mini App design guidelines and refactor layout components
- Updated Mini App design guidelines to include detailed instructions on UI changes, accessibility rules, and verification processes. - Refactored multiple components to utilize `MiniAppScreen` and `MiniAppScreenContent` for consistent layout structure across the application. - Improved error handling in `GlobalError` and `NotFound` components by integrating new layout components for better user experience. - Introduced new hooks for admin functionality, streamlining access checks and data loading processes. - Enhanced documentation to reflect changes in design policies and component usage, ensuring clarity for future development.
This commit is contained in:
116
webapp-next/src/components/admin/hooks/use-admin-reassign.ts
Normal file
116
webapp-next/src/components/admin/hooks/use-admin-reassign.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useState, type Dispatch, type SetStateAction } from "react";
|
||||
import { AccessDeniedError, patchAdminDuty, type UserForAdmin } from "@/lib/api";
|
||||
import { triggerHapticLight } from "@/lib/telegram-haptic";
|
||||
import type { DutyWithUser } from "@/types";
|
||||
|
||||
export interface UseAdminReassignOptions {
|
||||
initDataRaw: string | undefined;
|
||||
lang: "ru" | "en";
|
||||
users: UserForAdmin[];
|
||||
setDuties: Dispatch<SetStateAction<DutyWithUser[]>>;
|
||||
t: (key: string, params?: Record<string, string>) => string;
|
||||
}
|
||||
|
||||
export function useAdminReassign({
|
||||
initDataRaw,
|
||||
lang,
|
||||
users,
|
||||
setDuties,
|
||||
t,
|
||||
}: UseAdminReassignOptions) {
|
||||
const [selectedDuty, setSelectedDuty] = useState<DutyWithUser | null>(null);
|
||||
const [selectedUserId, setSelectedUserId] = useState<number | "">("");
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [reassignErrorKey, setReassignErrorKey] = useState<string | null>(null);
|
||||
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
||||
const [sheetExiting, setSheetExiting] = useState(false);
|
||||
|
||||
const closeReassign = useCallback(() => {
|
||||
setSelectedDuty(null);
|
||||
setSelectedUserId("");
|
||||
setReassignErrorKey(null);
|
||||
setSheetExiting(false);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!sheetExiting) return;
|
||||
const fallback = window.setTimeout(() => {
|
||||
closeReassign();
|
||||
}, 320);
|
||||
return () => window.clearTimeout(fallback);
|
||||
}, [sheetExiting, closeReassign]);
|
||||
|
||||
const openReassign = useCallback((duty: DutyWithUser) => {
|
||||
setSelectedDuty(duty);
|
||||
setSelectedUserId(duty.user_id);
|
||||
setReassignErrorKey(null);
|
||||
}, []);
|
||||
|
||||
const requestCloseSheet = useCallback(() => {
|
||||
setSheetExiting(true);
|
||||
}, []);
|
||||
|
||||
const handleReassign = useCallback(() => {
|
||||
if (!selectedDuty || selectedUserId === "" || !initDataRaw) return;
|
||||
if (selectedUserId === selectedDuty.user_id) {
|
||||
closeReassign();
|
||||
return;
|
||||
}
|
||||
setSaving(true);
|
||||
setReassignErrorKey(null);
|
||||
patchAdminDuty(selectedDuty.id, selectedUserId, initDataRaw, lang)
|
||||
.then((updated) => {
|
||||
setDuties((prev) =>
|
||||
prev.map((d) =>
|
||||
d.id === updated.id
|
||||
? {
|
||||
...d,
|
||||
user_id: updated.user_id,
|
||||
full_name:
|
||||
users.find((u) => u.id === updated.user_id)?.full_name ?? d.full_name,
|
||||
}
|
||||
: d
|
||||
)
|
||||
);
|
||||
setSuccessMessage(t("admin.reassign_success"));
|
||||
try {
|
||||
triggerHapticLight();
|
||||
} catch {
|
||||
// Haptic not available (e.g. non-Telegram).
|
||||
}
|
||||
requestCloseSheet();
|
||||
setTimeout(() => setSuccessMessage(null), 3000);
|
||||
})
|
||||
.catch((e) => {
|
||||
if (e instanceof AccessDeniedError) {
|
||||
setReassignErrorKey("admin.reassign_error_denied");
|
||||
} else if (e instanceof Error && /not found|не найден/i.test(e.message)) {
|
||||
setReassignErrorKey("admin.reassign_error_not_found");
|
||||
} else if (
|
||||
e instanceof TypeError ||
|
||||
(e instanceof Error && (e.message === "Failed to fetch" || e.message === "Load failed"))
|
||||
) {
|
||||
setReassignErrorKey("admin.reassign_error_network");
|
||||
} else {
|
||||
setReassignErrorKey("admin.reassign_error_generic");
|
||||
}
|
||||
})
|
||||
.finally(() => setSaving(false));
|
||||
}, [selectedDuty, selectedUserId, initDataRaw, lang, users, closeReassign, requestCloseSheet, t, setDuties]);
|
||||
|
||||
return {
|
||||
selectedDuty,
|
||||
selectedUserId,
|
||||
setSelectedUserId,
|
||||
saving,
|
||||
reassignErrorKey,
|
||||
successMessage,
|
||||
sheetExiting,
|
||||
openReassign,
|
||||
requestCloseSheet,
|
||||
handleReassign,
|
||||
closeReassign,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user