'use client'; import { useEffect, useMemo, useState } from 'react'; import Link from 'next/link'; import { ArrowRight, Download, ShieldCheck, Smartphone, Sparkles } from 'lucide-react'; import { BrandLogo } from '@/components/id/brand-logo'; import { usePublicSettings } from '@/components/id/public-settings-provider'; import { Button } from '@/components/ui/button'; import { AppRelease, buildAppReleaseDownloadUrl, fetchPublicAppReleases } from '@/lib/api'; function formatBytes(value: string) { const size = Number(value); if (!Number.isFinite(size) || size <= 0) return '—'; const units = ['Б', 'КБ', 'МБ', 'ГБ']; let amount = size; let unit = 0; while (amount >= 1024 && unit < units.length - 1) { amount /= 1024; unit += 1; } return `${amount.toFixed(amount >= 10 || unit === 0 ? 0 : 1)} ${units[unit]}`; } function formatDate(value: string) { return new Intl.DateTimeFormat('ru-RU', { day: '2-digit', month: 'long', year: 'numeric' }).format(new Date(value)); } export default function DownloadsPage() { const { projectName } = usePublicSettings(); const [releases, setReleases] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { void (async () => { try { const response = await fetchPublicAppReleases('ANDROID'); setReleases(response.releases ?? []); } finally { setLoading(false); } })(); }, []); const latestRelease = useMemo( () => releases.find((item) => item.platform === 'ANDROID') ?? null, [releases] ); const androidHistory = useMemo( () => releases.filter((item) => item.platform === 'ANDROID'), [releases] ); return (
Официальная сборка {projectName}

Скачайте приложение

Актуальная версия для Android. Каждый релиз подписан SHA-256 — мобильное приложение может автоматически проверять обновления по коду версии.

Android

Скачайте APK для телефона или планшета

{loading ? (

Проверяем доступные версии...

) : latestRelease ? ( <>

Последняя версия

v{latestRelease.version} build {latestRelease.versionCode}

{formatBytes(latestRelease.fileSize)} · {formatDate(latestRelease.createdAt)}

{latestRelease.releaseNotes ? (

{latestRelease.releaseNotes}

) : null} ) : (

Сборка для Android пока не опубликована.

)}

История версий

{loading ? (

Загружаем список версий...

) : androidHistory.length ? ( androidHistory.map((release, index) => (
v{release.version} build {release.versionCode} {index === 0 ? ( Актуальная ) : null}

{formatDate(release.createdAt)} · {formatBytes(release.fileSize)}

)) ) : (

Версии пока не опубликованы.

)}

Проверка обновлений в приложении

Мобильный клиент может запрашивать{' '} GET /idp-api/releases/check?platform=ANDROID&versionCode=...{' '} и сравнивать SHA-256 перед установкой. Постоянная ссылка на последнюю версию: /downloads/android

); }