Files
redefined-designs/frontend/src/main.tsx
T
bermudalambandClaude Opus 5 77e58c0b92 fix(admin): confirm writes succeeded and allow inline category creation (#23)
Reported from testing: the item form said "Item added" for a save that
never happened.

saveItem and the other admin calls returned res.json() without checking
res.ok, so a 4xx/5xx resolved normally and every caller reported success
for a write the server had rejected. That is worse than failing outright,
because nothing prompts the user to look for the missing row. All admin
calls now throw on a non-OK response, and the handlers report the error,
keep the form open so entered values survive, and only claim success once
the server has accepted the write. Mark sold/available previously did
nothing visible on failure at all.

Categories can now be created from the item form, as tags already could.
Previously a category that did not exist yet meant abandoning a
half-filled form for the Categories tab. New categories are created at
the top level; nesting stays in the Categories tab.

The control lives in its own component: inline, every keystroke
re-rendered the whole Inventory component and rebuilt the category tree,
which visibly jittered the open popup. It sits above the tree rather than
below it, where a long list both hid it and made its position depend on
the list's measured height. The tree no longer expands everything on
open, which does not scale past a screenful; it has search instead.

The app now honours prefers-reduced-motion by disabling antd transitions,
and the e2e suite runs with that preference set.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 11:07:44 -05:00

77 lines
2.7 KiB
TypeScript
Executable File

import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { ConfigProvider, theme as antdTheme } from 'antd';
import 'antd/dist/reset.css';
import App from './App';
import Admin from './admin/Admin';
import Login from './customer/Login';
import Register from './customer/Register';
import Account from './customer/Account';
import PrivacyPolicy from './customer/PrivacyPolicy';
import VerifyEmail from './customer/VerifyEmail';
import Cart from './cart/Cart';
import { CustomerAuthProvider } from './customer/CustomerAuthContext';
import { CartProvider } from './cart/CartContext';
import { ThemeModeProvider, useThemeMode } from './theme/ThemeContext';
import './styles.css';
const REDUCED_MOTION_QUERY = '(prefers-reduced-motion: reduce)';
// Respects the OS-level "reduce motion" accessibility setting by turning off
// antd's transitions. Beyond the accessibility win, animated popups are a
// standing source of flake in end-to-end tests, which drive the app with this
// preference enabled.
function usePrefersReducedMotion(): boolean {
const [prefers, setPrefers] = useState(
() => typeof window !== 'undefined' && window.matchMedia(REDUCED_MOTION_QUERY).matches
);
useEffect(() => {
const query = window.matchMedia(REDUCED_MOTION_QUERY);
const update = () => setPrefers(query.matches);
query.addEventListener('change', update);
return () => query.removeEventListener('change', update);
}, []);
return prefers;
}
function Root() {
const { mode } = useThemeMode();
const prefersReducedMotion = usePrefersReducedMotion();
return (
<ConfigProvider
theme={{
algorithm: mode === 'dark' ? antdTheme.darkAlgorithm : antdTheme.defaultAlgorithm,
token: { colorPrimary: '#1a1a1a', motion: !prefersReducedMotion }
}}
>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/admin" element={<Admin />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/account" element={<Account />} />
<Route path="/cart" element={<Cart />} />
<Route path="/privacy" element={<PrivacyPolicy />} />
<Route path="/verify-email" element={<VerifyEmail />} />
</Routes>
</BrowserRouter>
</ConfigProvider>
);
}
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<ThemeModeProvider>
<CustomerAuthProvider>
<CartProvider>
<Root />
</CartProvider>
</CustomerAuthProvider>
</ThemeModeProvider>
</React.StrictMode>
);