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:
217
docs/miniapp-design.md
Normal file
217
docs/miniapp-design.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# Mini App Design Guideline
|
||||
|
||||
This document defines the design rules for the Duty Teller Mini App (Next.js frontend in `webapp-next/`). It aligns with [Telegram’s official Mini App design guidelines](https://core.telegram.org/bots/webapps#designing-mini-apps) (Color Schemes and Design Guidelines) and codifies the current implementation (calendar, duty list, admin) as the reference for new screens and components.
|
||||
|
||||
---
|
||||
|
||||
## 1. Telegram design principles
|
||||
|
||||
Telegram’s guidelines state:
|
||||
|
||||
- **Mobile-first:** All elements must be responsive and designed for mobile first.
|
||||
- **Consistency:** Interactive elements should match the style, behaviour, and intent of existing Telegram UI components.
|
||||
- **Performance:** Animations should be smooth, ideally 60fps.
|
||||
- **Accessibility:** Inputs and images must have labels.
|
||||
- **Theme:** The app must use the dynamic theme-based colors provided by the API (Day/Night and custom themes).
|
||||
- **Safe areas:** The interface must respect the **safe area** and **content safe area** so content does not overlap system or Telegram UI, especially in fullscreen.
|
||||
- **Android:** On Android, use the extra User-Agent data (e.g. performance class) and reduce animations and effects on low-performance devices for smooth operation.
|
||||
|
||||
**Color schemes:** Mini Apps receive the user’s current **theme** in real time. Use the `ThemeParams` object and the CSS variables Telegram exposes (e.g. `--tg-theme-bg-color`, `--tg-theme-text-color`) so the UI adapts when the user switches Day/Night or custom themes.
|
||||
|
||||
---
|
||||
|
||||
## 2. Theme and colors
|
||||
|
||||
### 2.1 Sources
|
||||
|
||||
Theme is resolved in this order:
|
||||
|
||||
1. Hash parameters: `tgWebAppColorScheme`, `tgWebAppThemeParams` (parsed in the inline script in `webapp-next/src/app/layout.tsx`).
|
||||
2. At runtime: `Telegram.WebApp.colorScheme` and `Telegram.WebApp.themeParams` via `use-telegram-theme.ts` and `TelegramProvider`.
|
||||
|
||||
The inline script in the layout maps all Telegram theme keys to `--tg-theme-*` CSS variables on the document root. The hook sets `data-theme` (`light` / `dark`) and applies Mini App background/header colors.
|
||||
|
||||
### 2.2 Mapping (ThemeParams → app tokens)
|
||||
|
||||
In `webapp-next/src/app/globals.css`, `:root` and `[data-theme="light"]` / `[data-theme="dark"]` map Telegram’s ThemeParams to internal design tokens:
|
||||
|
||||
| Telegram ThemeParam (CSS var) | App token / usage |
|
||||
|--------------------------------------|-------------------|
|
||||
| `--tg-theme-bg-color` | `--bg` (background) |
|
||||
| `--tg-theme-secondary-bg-color` | `--surface` (cards, panels) |
|
||||
| `--tg-theme-text-color` | `--text` (primary text) |
|
||||
| `--tg-theme-hint-color`, `--tg-theme-subtitle-text-color` | `--muted` (secondary text) |
|
||||
| `--tg-theme-link-color` | `--accent` (links, secondary actions) |
|
||||
| `--tg-theme-header-bg-color` | `--header-bg` |
|
||||
| `--tg-theme-section-bg-color` | `--card` (sections) |
|
||||
| `--tg-theme-section-header-text-color` | `--section-header` |
|
||||
| `--tg-theme-section-separator-color` | `--border` |
|
||||
| `--tg-theme-button-color` | `--primary` |
|
||||
| `--tg-theme-button-text-color` | `--primary-foreground` |
|
||||
| `--tg-theme-destructive-text-color` | `--error` |
|
||||
| `--tg-theme-accent-text-color` | `--accent-text` |
|
||||
|
||||
Tailwind/shadcn semantic tokens are wired to these: `--background` → `--bg`, `--foreground` → `--text`, `--primary`, `--secondary` → `--surface`, etc.
|
||||
|
||||
### 2.3 Domain colors
|
||||
|
||||
Duty-specific semantics (fixed per theme, not from ThemeParams):
|
||||
|
||||
- `--duty` — duty shift (e.g. green).
|
||||
- `--unavailable` — unavailable (e.g. amber).
|
||||
- `--vacation` — vacation (e.g. blue).
|
||||
- `--today` — “today” highlight; tied to `--tg-theme-accent-text-color` / `--tg-theme-link-color`.
|
||||
|
||||
Use Tailwind classes such as `bg-duty`, `border-l-unavailable`, `text-today`, `bg-today`, etc.
|
||||
|
||||
### 2.4 Derived tokens (color-mix)
|
||||
|
||||
Prefer these instead of ad-hoc color mixes:
|
||||
|
||||
- `--surface-hover`, `--surface-hover-10` — hover states for surfaces.
|
||||
- `--surface-today-tint`, `--surface-muted-tint` — subtle tints.
|
||||
- `--today-hover`, `--today-border`, `--today-border-selected`, `--today-gradient-end` — today state.
|
||||
- `--muted-fade`, `--shadow-card`, etc.
|
||||
|
||||
Defined in `globals.css`; use via `var(--surface-hover)` in classes (e.g. `hover:bg-[var(--surface-hover)]`).
|
||||
|
||||
### 2.5 Rule for new work
|
||||
|
||||
Use **only** these tokens and Tailwind/shadcn aliases (`bg-background`, `text-muted`, `bg-surface`, `text-accent`, `border-l-duty`, `bg-today`, etc.). Do not hardcode hex or RGB in new components or screens.
|
||||
|
||||
---
|
||||
|
||||
## 3. Layout and safe areas
|
||||
|
||||
### 3.1 Width
|
||||
|
||||
- **Token:** `--max-width-app: 420px` (in `@theme` in `globals.css`).
|
||||
- **Usage:** Page wrapper uses `max-w-[var(--max-width-app)]` (e.g. in `page.tsx`, `CalendarPage.tsx`, `admin/page.tsx`). Content is centred with `mx-auto`.
|
||||
|
||||
### 3.2 Height
|
||||
|
||||
- **Viewport:** Prefer `min-h-[var(--tg-viewport-stable-height,100vh)]` for the main content area so the Mini App fills the visible height correctly when expanded/collapsed. Fallback `100vh` when not in Telegram.
|
||||
- **Body:** In `globals.css`, `body` already has `min-height: var(--tg-viewport-stable-height, 100vh)` and `background: var(--bg)`.
|
||||
|
||||
### 3.3 Safe area and content safe area
|
||||
|
||||
- **Class `.content-safe`** (in `globals.css`): Applies:
|
||||
- `padding-top: var(--tg-viewport-content-safe-area-inset-top, env(safe-area-inset-top, 0))`
|
||||
- `padding-bottom: var(--tg-viewport-content-safe-area-inset-bottom, env(safe-area-inset-bottom, 0))`
|
||||
- Use `.content-safe` on the **root container of each page** so content is not covered by the Telegram header or bottom bar (Bot API 8.0+).
|
||||
- Lists that extend to the bottom should also account for bottom inset (e.g. `padding-bottom: var(--tg-viewport-content-safe-area-inset-bottom, 12px)` in `.container-app`).
|
||||
|
||||
### 3.4 Sheets and modals
|
||||
|
||||
Bottom sheets and modals that sit at the bottom of the screen must add safe area to their padding, e.g.:
|
||||
|
||||
`pb-[calc(24px+env(safe-area-inset-bottom,0px))]`
|
||||
|
||||
See `webapp-next/src/components/day-detail/DayDetail.tsx` for the Sheet content.
|
||||
|
||||
---
|
||||
|
||||
## 4. Typography and spacing
|
||||
|
||||
### 4.1 Font
|
||||
|
||||
- **Family:** `system-ui, -apple-system, sans-serif` (set in `globals.css` and Tailwind theme).
|
||||
|
||||
### 4.2 Patterns from the calendar and duty list
|
||||
|
||||
| Element | Classes / tokens |
|
||||
|--------|-------------------|
|
||||
| Month title | `text-[1.1rem]` / `sm:text-[1.25rem]`, `font-semibold` |
|
||||
| Year (above month) | `text-xs`, `text-muted` |
|
||||
| Nav buttons (prev/next month) | `size-10`, `rounded-[10px]` |
|
||||
| Calendar day cell | `text-[0.85rem]`, `rounded-lg`, `p-1` |
|
||||
| Duty timeline card | `px-2.5 py-2`, `rounded-lg` |
|
||||
|
||||
### 4.3 Page and block spacing
|
||||
|
||||
- Page container: `px-3 pb-6` in addition to `.content-safe`.
|
||||
- Between sections: `mb-3`, `mb-4` as appropriate.
|
||||
- Grids: `gap-1` for tight layouts (e.g. calendar grid), larger gaps where needed.
|
||||
|
||||
---
|
||||
|
||||
## 5. Component patterns
|
||||
|
||||
### 5.1 Buttons
|
||||
|
||||
- **Primary:** Use the default Button variant: `bg-primary text-primary-foreground` (from `webapp-next/src/components/ui/button.tsx`).
|
||||
- **Secondary icon buttons** (e.g. calendar nav):
|
||||
`bg-surface text-accent hover:bg-[var(--surface-hover)] focus-visible:outline-accent active:scale-95`
|
||||
with `size-10` and `rounded-[10px]`.
|
||||
- Keep focus visible (e.g. `focus-visible:outline-accent` or ring); do not remove outline without a visible replacement.
|
||||
|
||||
### 5.2 Cards
|
||||
|
||||
- **Background:** `bg-surface` or `bg-card` (both resolve to theme tokens).
|
||||
- **Borders:** `border`, `--border` (section separator color).
|
||||
- **Emphasis:** `var(--shadow-card)` for highlighted cards (e.g. current duty).
|
||||
- **Left stripe by type:** `border-l-[3px]` with:
|
||||
- `border-l-duty`, `border-l-unavailable`, `border-l-vacation` for event types;
|
||||
- `border-l-today` for “current duty” (see `.border-l-today` in `globals.css`).
|
||||
|
||||
### 5.3 Calendar grid
|
||||
|
||||
- **Structure:** 7 columns × 6 rows; use `role="grid"` on the container and `role="gridcell"` on each cell.
|
||||
- **Layout:** `min-h-[var(--calendar-grid-min-height)]`, cells `aspect-square` with `min-h-8`, `rounded-lg`, `gap-1`.
|
||||
- **Today:** `bg-today text-[var(--bg)]`; hover `hover:bg-[var(--today-hover)]`.
|
||||
- **Other month:** `opacity-40`, `pointer-events-none`, `bg-[var(--surface-muted-tint)]`.
|
||||
|
||||
### 5.4 Timeline list (duties)
|
||||
|
||||
- **Dates:** Horizontal line and vertical tick from shared CSS in `globals.css`:
|
||||
`.duty-timeline-date`, `.duty-timeline-date--today` (with `::before` / `::after`).
|
||||
- **Cards:** Same card rules as above; `border-l-[3px]` + type class; optional flip card for contacts (see `DutyTimelineCard.tsx`).
|
||||
|
||||
---
|
||||
|
||||
## 6. Motion and performance
|
||||
|
||||
### 6.1 Timing
|
||||
|
||||
- **Tokens:** `--transition-fast: 0.15s`, `--transition-normal: 0.25s`, `--ease-out: cubic-bezier(0.32, 0.72, 0, 1)`.
|
||||
- Use these for transitions and short animations so behaviour is consistent and predictable.
|
||||
|
||||
### 6.2 Reduced motion
|
||||
|
||||
- **Rule:** `@media (prefers-reduced-motion: reduce)` in `globals.css` shortens animation and transition durations globally. New animations should remain optional or short so they degrade gracefully when reduced.
|
||||
|
||||
### 6.3 Android low-performance devices
|
||||
|
||||
- **Detection:** `webapp-next/src/lib/telegram-android-perf.ts` reads Telegram’s User-Agent and sets `data-perf="low"` on the document root when the device performance class is LOW.
|
||||
- **CSS:** `[data-perf="low"] *` in `globals.css` minimizes animation/transition duration. Avoid adding heavy or long animations without considering this; prefer simple or no animation on low-end devices.
|
||||
|
||||
---
|
||||
|
||||
## 7. Accessibility
|
||||
|
||||
- **Focus:** Use `focus-visible:outline-accent` (or equivalent ring) on interactive elements; do not remove focus outline without a visible alternative.
|
||||
- **Calendar:** Use `role="grid"` and `role="gridcell"`, `aria-label` on nav buttons (e.g. “Previous month”), and a composite `aria-label` on each day cell (date + event types). See `webapp-next/src/components/calendar/CalendarDay.tsx`.
|
||||
- **Images and inputs:** Always provide labels (per Telegram’s guidelines and WCAG).
|
||||
|
||||
---
|
||||
|
||||
## 8. Telegram integration
|
||||
|
||||
- **Header and background:** On init (layout script and `use-telegram-theme.ts`), call:
|
||||
- `setBackgroundColor('bg_color')`
|
||||
- `setHeaderColor('bg_color')`
|
||||
- `setBottomBarColor('bottom_bar_bg_color')` when available (Bot API 7.10+).
|
||||
- **Surface contrast:** When `--surface` equals `--bg` (e.g. some iOS OLED themes), `fixSurfaceContrast()` in `use-telegram-theme.ts` adjusts `--surface` using ThemeParams or a light color-mix so cards and panels remain visible.
|
||||
|
||||
---
|
||||
|
||||
## 9. Checklist for new screens and components
|
||||
|
||||
Use this for review when adding or changing UI:
|
||||
|
||||
- [ ] Use only design tokens from `globals.css` and Tailwind/shadcn aliases; no hardcoded colours.
|
||||
- [ ] Page wrapper has `.content-safe`, `max-w-[var(--max-width-app)]`, and appropriate min-height (viewport-stable-height or `min-h-screen` with fallback).
|
||||
- [ ] Buttons and cards follow the patterns above (variants, surfaces, border-l by type).
|
||||
- [ ] Safe area is respected for bottom padding and for sheets/modals.
|
||||
- [ ] Interactive elements and grids/lists have appropriate `aria-label`s and roles.
|
||||
- [ ] New animations respect `prefers-reduced-motion` and `data-perf="low"` (short or minimal on low-end Android).
|
||||
Reference in New Issue
Block a user