Files
duty-teller/webapp-next/src/hooks/use-app-init.ts
Nikolay Tatarinov 16bf1a1043 feat: migrate to Next.js for Mini App and enhance project structure
- Replaced the previous webapp with a new Mini App built using Next.js, improving performance and maintainability.
- Updated the `.gitignore` to exclude Next.js build artifacts and node modules.
- Revised documentation in `AGENTS.md`, `README.md`, and `architecture.md` to reflect the new Mini App structure and technology stack.
- Enhanced Dockerfile to support the new build process for the Next.js application.
- Updated CI workflow to build and test the Next.js application.
- Added new configuration options for the Mini App, including `MINI_APP_SHORT_NAME` for improved deep linking.
- Refactored frontend testing setup to accommodate the new structure and testing framework.
- Removed legacy webapp files and dependencies to streamline the project.
2026-03-03 16:04:08 +03:00

64 lines
2.2 KiB
TypeScript

/**
* Application initialization: language sync, access-denied logic, deep link routing.
* Runs effects that depend on Telegram auth (isAllowed, startParam); caller provides those.
*/
"use client";
import { useEffect } from "react";
import { useAppStore } from "@/store/app-store";
import { getLang } from "@/i18n/messages";
import { useTranslation } from "@/i18n/use-translation";
import { RETRY_DELAY_MS } from "@/lib/constants";
export interface UseAppInitParams {
/** Whether the user is allowed (localhost or has valid initData). */
isAllowed: boolean;
/** Telegram Mini App start_param (e.g. "duty" for current duty deep link). */
startParam: string | undefined;
}
/**
* Syncs language from backend config, applies document lang/title, handles access denied
* when not allowed, and routes to current duty view when opened via startParam=duty.
*/
export function useAppInit({ isAllowed, startParam }: UseAppInitParams): void {
const setLang = useAppStore((s) => s.setLang);
const lang = useAppStore((s) => s.lang);
const setAccessDenied = useAppStore((s) => s.setAccessDenied);
const setLoading = useAppStore((s) => s.setLoading);
const setCurrentView = useAppStore((s) => s.setCurrentView);
const { t } = useTranslation();
// Sync lang from backend config (window.__DT_LANG).
useEffect(() => {
if (typeof window === "undefined") return;
setLang(getLang());
}, [setLang]);
// Apply lang to document (title and html lang) for accessibility and i18n.
useEffect(() => {
if (typeof document === "undefined") return;
document.documentElement.lang = lang;
document.title = t("app.title");
}, [lang, t]);
// When not allowed (no initData and not localhost), show access denied after delay.
useEffect(() => {
if (isAllowed) {
setAccessDenied(false);
return;
}
const id = setTimeout(() => {
setAccessDenied(true);
setLoading(false);
}, RETRY_DELAY_MS);
return () => clearTimeout(id);
}, [isAllowed, setAccessDenied, setLoading]);
// When opened via deep link startParam=duty, show current duty view first.
useEffect(() => {
if (startParam === "duty") setCurrentView("currentDuty");
}, [startParam, setCurrentView]);
}