fix: resolve 6 Gitea issues (#9, #10, #12, #14, #15, #21)

- #21: Add missing await in removeChoiceIfPresent() to prevent user appearing in two restaurants
- #15: Add 1-hour TTL for menu refetching to avoid scraping on every page load
- #9: Block stats API and UI navigation for future dates
- #14: Add restaurant warnings (missing soup/prices, stale data) with warning icon
- #12: Pre-fill restaurant/departure dropdowns from existing choices on page refresh
- #10: Add voting statistics endpoint and table on stats page
This commit is contained in:
2026-02-04 13:18:27 +01:00
parent d85c764c88
commit 6f43c74769
11 changed files with 242 additions and 12 deletions

View File

@@ -13,7 +13,7 @@ import './App.scss';
import { faCircleCheck, faNoteSticky, faTrashCan, faComment } from '@fortawesome/free-regular-svg-icons';
import { useSettings } from './context/settings';
import Footer from './components/Footer';
import { faBasketShopping, faChainBroken, faChevronLeft, faChevronRight, faGear, faSatelliteDish, faSearch } from '@fortawesome/free-solid-svg-icons';
import { faBasketShopping, faChainBroken, faChevronLeft, faChevronRight, faGear, faSatelliteDish, faSearch, faTriangleExclamation } from '@fortawesome/free-solid-svg-icons';
import Loader from './components/Loader';
import { getHumanDateTime, isInTheFuture } from './Utils';
import NoteModal from './components/modals/NoteModal';
@@ -138,9 +138,33 @@ function App() {
}, [socket]);
useEffect(() => {
if (!auth?.login) {
if (!auth?.login || !data?.choices) {
return
}
// Pre-fill form refs from existing choices
let foundKey: LunchChoice | undefined;
let foundChoice: UserLunchChoice | undefined;
for (const key of Object.keys(data.choices)) {
const locationKey = key as LunchChoice;
const locationChoices = data.choices[locationKey];
if (locationChoices && auth.login in locationChoices) {
foundKey = locationKey;
foundChoice = locationChoices[auth.login];
break;
}
}
if (foundKey && choiceRef.current) {
choiceRef.current.value = foundKey;
const restaurantKey = Object.keys(Restaurant).indexOf(foundKey);
if (restaurantKey > -1 && food) {
const restaurant = Object.keys(Restaurant)[restaurantKey] as Restaurant;
setFoodChoiceList(food[restaurant]?.food);
setClosed(food[restaurant]?.closed ?? false);
}
}
if (foundChoice?.departureTime && departureChoiceRef.current) {
departureChoiceRef.current.value = foundChoice.departureTime;
}
}, [auth, auth?.login, data?.choices])
// Reference na mojí objednávku
@@ -388,6 +412,11 @@ function App() {
{getLunchChoiceName(location)}
</h3>
{menu?.lastUpdate && <small>Aktualizace: {getHumanDateTime(new Date(menu.lastUpdate))}</small>}
{menu?.warnings && menu.warnings.length > 0 && (
<span className="restaurant-warning" title={menu.warnings.join('\n')}>
<FontAwesomeIcon icon={faTriangleExclamation} />
</span>
)}
</div>
{content}
</div>