fix(web): drop FM square badge from Logo; better 404 diagnostics on MoySklad page

Logo simplified to just "FOOD" (black) + "MARKET" (brand green) text — matches
the app-icon style without the distracting FM badge square.

MoySklad import page now shows actionable error text instead of generic
"Request failed with status code 404":
- 404 → "эндпоинт не существует, API не перезапущен после git pull"
- 401 → "сессия истекла, перелогинься"
- 403 → "нужна роль Admin или SuperAdmin"
- 502/503 → "МойСклад недоступен"
- Otherwise extracts body.error / error_description / title from response

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
nurdotnet 2026-04-21 21:16:01 +05:00
parent 25f25f9171
commit cead88b0bc
4 changed files with 34 additions and 24 deletions

View file

@ -55,7 +55,7 @@ export function AppLayout() {
<div className="min-h-screen flex bg-slate-50 dark:bg-slate-950">
<aside className="w-60 flex-shrink-0 bg-white dark:bg-slate-900 border-r border-slate-200 dark:border-slate-800 flex flex-col">
<div className="h-14 flex items-center px-5 border-b border-slate-200 dark:border-slate-800">
<Logo size={28} />
<Logo />
</div>
<nav className="flex-1 overflow-y-auto py-3">

View file

@ -1,25 +1,17 @@
import { cn } from '@/lib/utils'
export function Logo({ size = 28, showText = true, className }: { size?: number; showText?: boolean; className?: string }) {
export function Logo({ className }: { className?: string }) {
return (
<div className={cn('flex items-center gap-2.5', className)}>
<div
className="flex items-center justify-center rounded-md font-black text-white leading-none"
style={{
backgroundColor: 'var(--color-brand)',
width: size,
height: size,
fontSize: Math.floor(size * 0.38),
}}
<div className={cn('flex flex-col leading-none select-none', className)}>
<span className="font-black text-slate-900 dark:text-slate-100 tracking-[0.08em] text-base">
FOOD
</span>
<span
className="font-black text-[11px] tracking-[0.24em] mt-0.5"
style={{ color: 'var(--color-brand)' }}
>
FM
</div>
{showText && (
<div className="leading-tight">
<div className="font-black text-slate-900 dark:text-slate-100 tracking-wide">FOOD</div>
<div className="font-black text-xs tracking-[0.2em]" style={{ color: 'var(--color-brand)' }}>MARKET</div>
</div>
)}
MARKET
</span>
</div>
)
}

View file

@ -33,9 +33,9 @@ export function LoginPage() {
onSubmit={handleSubmit}
className="w-full max-w-md bg-white dark:bg-slate-800 rounded-xl shadow-lg p-8 space-y-5"
>
<div className="space-y-3">
<Logo size={44} />
<p className="text-sm text-slate-500">Вход в систему</p>
<div>
<Logo />
<p className="text-sm text-slate-500 mt-2.5">Вход в систему</p>
</div>
<label className="block space-y-1.5">

View file

@ -1,11 +1,29 @@
import { useState } from 'react'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { AlertCircle, CheckCircle, Download, KeyRound } from 'lucide-react'
import { AxiosError } from 'axios'
import { api } from '@/lib/api'
import { PageHeader } from '@/components/PageHeader'
import { Button } from '@/components/Button'
import { Field, TextInput, Checkbox } from '@/components/Field'
function formatError(err: unknown): string {
if (err instanceof AxiosError) {
const status = err.response?.status
const body = err.response?.data as { error?: string; error_description?: string; title?: string } | undefined
const detail = body?.error ?? body?.error_description ?? body?.title
if (status === 404) {
return `404 Not Found — эндпоинт не существует. Вероятно, API не перезапущен после git pull. Сделай Ctrl+C → dotnet run.`
}
if (status === 401) return '401 Unauthorized — сессия истекла, перелогинься.'
if (status === 403) return '403 Forbidden — нужна роль Admin или SuperAdmin для этой операции.'
if (status === 502 || status === 503) return `${status} — МойСклад недоступен, попробуй позже.`
return detail ? `${status ?? ''} ${detail}` : err.message
}
if (err instanceof Error) return err.message
return String(err)
}
interface TestResponse { organization: string; inn?: string | null }
interface ImportResponse {
total: number
@ -78,7 +96,7 @@ export function MoySkladImportPage() {
)}
{test.error && (
<div className="text-sm text-red-600">
{(test.error as Error).message}
{formatError(test.error)}
</div>
)}
</div>
@ -138,7 +156,7 @@ export function MoySkladImportPage() {
{run.error && (
<div className="mt-5 p-3.5 rounded-md bg-red-50 dark:bg-red-950/20 border border-red-200 dark:border-red-900 text-sm text-red-700 dark:text-red-300">
Ошибка: {(run.error as Error).message}
Ошибка: {formatError(run.error)}
</div>
)}
</div>