mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
71c1683bb3
- Add visited_regions table migration - Mark/unmark region endpoints with auto-mark parent country - Unmark country cascades to its regions; unmark last region cascades to country - Region modal with mark/unmark flow and bucket list shortcut - Viewport-based lazy loading of region GeoJSON at zoom >= 6 - i18n: add atlas.markRegionVisitedHint and atlas.confirmUnmarkRegion across all 13 locales
106 lines
3.9 KiB
TypeScript
106 lines
3.9 KiB
TypeScript
import express, { Request, Response } from 'express';
|
|
import { authenticate } from '../middleware/auth';
|
|
import { AuthRequest } from '../types';
|
|
import {
|
|
getStats,
|
|
getCountryPlaces,
|
|
markCountryVisited,
|
|
unmarkCountryVisited,
|
|
markRegionVisited,
|
|
unmarkRegionVisited,
|
|
getVisitedRegions,
|
|
getRegionGeo,
|
|
listBucketList,
|
|
createBucketItem,
|
|
updateBucketItem,
|
|
deleteBucketItem,
|
|
} from '../services/atlasService';
|
|
|
|
const router = express.Router();
|
|
router.use(authenticate);
|
|
|
|
router.get('/stats', async (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
const data = await getStats(userId);
|
|
res.json(data);
|
|
});
|
|
|
|
router.get('/regions', async (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
res.setHeader('Cache-Control', 'no-cache, no-store');
|
|
const data = await getVisitedRegions(userId);
|
|
res.json(data);
|
|
});
|
|
|
|
router.get('/regions/geo', async (req: Request, res: Response) => {
|
|
const countries = (req.query.countries as string || '').split(',').filter(Boolean);
|
|
if (countries.length === 0) return res.json({ type: 'FeatureCollection', features: [] });
|
|
const geo = await getRegionGeo(countries);
|
|
res.setHeader('Cache-Control', 'public, max-age=86400');
|
|
res.json(geo);
|
|
});
|
|
|
|
router.get('/country/:code', (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
const code = req.params.code.toUpperCase();
|
|
res.json(getCountryPlaces(userId, code));
|
|
});
|
|
|
|
router.post('/country/:code/mark', (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
markCountryVisited(userId, req.params.code.toUpperCase());
|
|
res.json({ success: true });
|
|
});
|
|
|
|
router.delete('/country/:code/mark', (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
unmarkCountryVisited(userId, req.params.code.toUpperCase());
|
|
res.json({ success: true });
|
|
});
|
|
|
|
router.post('/region/:code/mark', (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
const { name, country_code } = req.body;
|
|
if (!name || !country_code) return res.status(400).json({ error: 'name and country_code are required' });
|
|
markRegionVisited(userId, req.params.code.toUpperCase(), name, country_code.toUpperCase());
|
|
res.json({ success: true });
|
|
});
|
|
|
|
router.delete('/region/:code/mark', (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
unmarkRegionVisited(userId, req.params.code.toUpperCase());
|
|
res.json({ success: true });
|
|
});
|
|
|
|
// ── Bucket List ─────────────────────────────────────────────────────────────
|
|
|
|
router.get('/bucket-list', (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
res.json({ items: listBucketList(userId) });
|
|
});
|
|
|
|
router.post('/bucket-list', (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
const { name, lat, lng, country_code, notes, target_date } = req.body;
|
|
if (!name?.trim()) return res.status(400).json({ error: 'Name is required' });
|
|
const item = createBucketItem(userId, { name, lat, lng, country_code, notes, target_date });
|
|
res.status(201).json({ item });
|
|
});
|
|
|
|
router.put('/bucket-list/:id', (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
const { name, notes, lat, lng, country_code, target_date } = req.body;
|
|
const item = updateBucketItem(userId, req.params.id, { name, notes, lat, lng, country_code, target_date });
|
|
if (!item) return res.status(404).json({ error: 'Item not found' });
|
|
res.json({ item });
|
|
});
|
|
|
|
router.delete('/bucket-list/:id', (req: Request, res: Response) => {
|
|
const userId = (req as AuthRequest).user.id;
|
|
const deleted = deleteBucketItem(userId, req.params.id);
|
|
if (!deleted) return res.status(404).json({ error: 'Item not found' });
|
|
res.json({ success: true });
|
|
});
|
|
|
|
export default router;
|