feat: implement admin panel functionality in Mini App

- Added new API endpoints for admin features: `GET /api/admin/me`, `GET /api/admin/users`, and `PATCH /api/admin/duties/:id` to manage user duties.
- Introduced `UserForAdmin` and `AdminDutyReassignBody` schemas for handling admin-related data.
- Updated documentation to include Mini App design guidelines and admin panel functionalities.
- Enhanced tests for admin API to ensure proper access control and functionality.
- Improved error handling and localization for admin actions.
This commit is contained in:
2026-03-06 09:57:26 +03:00
parent 68b1884b73
commit c390a4dd6e
28 changed files with 2045 additions and 15 deletions

View File

@@ -30,6 +30,8 @@ export interface AppState {
selectedDay: string | null;
/** True when the first visible screen has finished loading; used to hide content until ready(). */
appContentReady: boolean;
/** True when GET /api/admin/me returned is_admin: true; used to show Admin link. */
isAdmin: boolean;
setCurrentMonth: (d: Date) => void;
nextMonth: () => void;
@@ -44,8 +46,9 @@ export interface AppState {
setCurrentView: (v: CurrentView) => void;
setSelectedDay: (key: string | null) => void;
setAppContentReady: (v: boolean) => void;
setIsAdmin: (v: boolean) => void;
/** Batch multiple state updates into a single re-render. */
batchUpdate: (partial: Partial<Pick<AppState, "currentMonth" | "pendingMonth" | "lang" | "duties" | "calendarEvents" | "dataForMonthKey" | "loading" | "error" | "accessDenied" | "accessDeniedDetail" | "currentView" | "selectedDay" | "appContentReady">>) => void;
batchUpdate: (partial: Partial<Pick<AppState, "currentMonth" | "pendingMonth" | "lang" | "duties" | "calendarEvents" | "dataForMonthKey" | "loading" | "error" | "accessDenied" | "accessDeniedDetail" | "currentView" | "selectedDay" | "appContentReady" | "isAdmin">>) => void;
}
const now = new Date();
@@ -71,6 +74,7 @@ export const useAppStore = create<AppState>((set) => ({
currentView: getInitialView(),
selectedDay: null,
appContentReady: false,
isAdmin: false,
setCurrentMonth: (d) => set({ currentMonth: d }),
nextMonth: () =>
@@ -91,5 +95,6 @@ export const useAppStore = create<AppState>((set) => ({
setCurrentView: (v) => set({ currentView: v }),
setSelectedDay: (key) => set({ selectedDay: key }),
setAppContentReady: (v) => set({ appContentReady: v }),
setIsAdmin: (v) => set({ isAdmin: v }),
batchUpdate: (partial) => set(partial),
}));