mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 16:03:02 +00:00
add Google Maps route import and plugin corridor search
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'استيراد مسار Google Maps',
|
||||
'roadtrip.import.note': 'تُضاف المحطات إلى اليوم المحدد. يعيد TREK حساب المسار.',
|
||||
'roadtrip.import.unresolved': 'تعذر تحديد الموقع؛ سيتم تخطي هذه المحطة.',
|
||||
'roadtrip.import.day': 'اليوم',
|
||||
'roadtrip.hazards.show': 'عرض مناطق الخطر',
|
||||
'roadtrip.hazards.current': 'التحذيرات الحالية',
|
||||
'roadtrip.hazards.note': 'التحذيرات لا تعني إغلاق الطرق. يبقى المسار دون تغيير.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Importar rota do Google Maps',
|
||||
'roadtrip.import.note': 'As paradas são adicionadas ao dia escolhido. O TREK recalcula a rota.',
|
||||
'roadtrip.import.unresolved': 'Local não encontrado; esta parada será ignorada.',
|
||||
'roadtrip.import.day': 'Dia',
|
||||
'roadtrip.hazards.show': 'Mostrar áreas de risco',
|
||||
'roadtrip.hazards.current': 'Alertas atuais',
|
||||
'roadtrip.hazards.note': 'Alertas não são interdições de vias. A rota não muda.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Importa una ruta de Google Maps',
|
||||
'roadtrip.import.note': 'Les parades s’afegeixen al dia triat. TREK recalcula la ruta.',
|
||||
'roadtrip.import.unresolved': 'Ubicació no trobada; aquesta parada s’ometrà.',
|
||||
'roadtrip.import.day': 'Dia',
|
||||
'roadtrip.hazards.show': 'Mostra zones de perill',
|
||||
'roadtrip.hazards.current': 'Avisos actuals',
|
||||
'roadtrip.hazards.note': 'Els avisos no són talls de carretera. La ruta no canvia.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Importovat trasu z Google Maps',
|
||||
'roadtrip.import.note': 'Zastávky se přidají ke zvolenému dni. TREK trasu přepočítá.',
|
||||
'roadtrip.import.unresolved': 'Místo nenalezeno; tato zastávka bude přeskočena.',
|
||||
'roadtrip.import.day': 'Den',
|
||||
'roadtrip.hazards.show': 'Zobrazit nebezpečné oblasti',
|
||||
'roadtrip.hazards.current': 'Aktuální výstrahy',
|
||||
'roadtrip.hazards.note': 'Výstrahy nejsou uzavírky silnic. Trasa se nemění.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Google-Maps-Route importieren',
|
||||
'roadtrip.import.note': 'Stopps werden an den gewählten Tag angehängt. TREK berechnet die Route neu.',
|
||||
'roadtrip.import.unresolved': 'Ort nicht gefunden; dieser Stopp wird übersprungen.',
|
||||
'roadtrip.import.day': 'Tag',
|
||||
'roadtrip.hazards.show': 'Gefahrengebiete anzeigen',
|
||||
'roadtrip.hazards.current': 'Aktuelle Warnungen',
|
||||
'roadtrip.hazards.note': 'Warnungen sind keine Straßensperrungen. Die Route bleibt unverändert.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Import Google Maps route',
|
||||
'roadtrip.import.note': 'Stops are appended to the selected day. TREK recalculates the route.',
|
||||
'roadtrip.import.unresolved': 'Location unresolved; this stop will be skipped.',
|
||||
'roadtrip.import.day': 'Day',
|
||||
'roadtrip.hazards.show': 'Show hazard areas',
|
||||
'roadtrip.hazards.current': 'Current warnings',
|
||||
'roadtrip.hazards.note': 'Warnings are not road closures. Routes stay unchanged.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Importar ruta de Google Maps',
|
||||
'roadtrip.import.note': 'Las paradas se añaden al día elegido. TREK recalcula la ruta.',
|
||||
'roadtrip.import.unresolved': 'Ubicación no encontrada; se omitirá esta parada.',
|
||||
'roadtrip.import.day': 'Día',
|
||||
'roadtrip.hazards.show': 'Mostrar zonas de peligro',
|
||||
'roadtrip.hazards.current': 'Alertas actuales',
|
||||
'roadtrip.hazards.note': 'Las alertas no son cierres de carreteras. La ruta no cambia.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Importer un itinéraire Google Maps',
|
||||
'roadtrip.import.note': 'Les étapes sont ajoutées au jour choisi. TREK recalcule le trajet.',
|
||||
'roadtrip.import.unresolved': 'Lieu introuvable ; cette étape sera ignorée.',
|
||||
'roadtrip.import.day': 'Jour',
|
||||
'roadtrip.hazards.show': 'Afficher les zones à risque',
|
||||
'roadtrip.hazards.current': 'Alertes actuelles',
|
||||
'roadtrip.hazards.note': 'Les alertes ne sont pas des fermetures de routes. Le trajet reste inchangé.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Εισαγωγή διαδρομής Google Maps',
|
||||
'roadtrip.import.note': 'Οι στάσεις προστίθενται στην επιλεγμένη ημέρα. Το TREK υπολογίζει ξανά τη διαδρομή.',
|
||||
'roadtrip.import.unresolved': 'Η τοποθεσία δεν βρέθηκε· αυτή η στάση θα παραλειφθεί.',
|
||||
'roadtrip.import.day': 'Ημέρα',
|
||||
'roadtrip.hazards.show': 'Εμφάνιση επικίνδυνων περιοχών',
|
||||
'roadtrip.hazards.current': 'Τρέχουσες προειδοποιήσεις',
|
||||
'roadtrip.hazards.note': 'Οι προειδοποιήσεις δεν σημαίνουν κλειστούς δρόμους. Η διαδρομή δεν αλλάζει.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Google Maps-útvonal importálása',
|
||||
'roadtrip.import.note': 'A megállók a kiválasztott naphoz kerülnek. A TREK újratervezi az útvonalat.',
|
||||
'roadtrip.import.unresolved': 'A hely nem található; ez a megálló kimarad.',
|
||||
'roadtrip.import.day': 'Nap',
|
||||
'roadtrip.hazards.show': 'Veszélyes területek megjelenítése',
|
||||
'roadtrip.hazards.current': 'Aktuális figyelmeztetések',
|
||||
'roadtrip.hazards.note': 'A figyelmeztetések nem útlezárások. Az útvonal változatlan marad.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Impor rute Google Maps',
|
||||
'roadtrip.import.note': 'Perhentian ditambahkan ke hari yang dipilih. TREK menghitung ulang rute.',
|
||||
'roadtrip.import.unresolved': 'Lokasi tidak ditemukan; perhentian ini akan dilewati.',
|
||||
'roadtrip.import.day': 'Hari',
|
||||
'roadtrip.hazards.show': 'Tampilkan area bahaya',
|
||||
'roadtrip.hazards.current': 'Peringatan terkini',
|
||||
'roadtrip.hazards.note': 'Peringatan bukan penutupan jalan. Rute tidak berubah.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Importa percorso Google Maps',
|
||||
'roadtrip.import.note': 'Le tappe vengono aggiunte al giorno scelto. TREK ricalcola il percorso.',
|
||||
'roadtrip.import.unresolved': 'Posizione non trovata; questa tappa verrà saltata.',
|
||||
'roadtrip.import.day': 'Giorno',
|
||||
'roadtrip.hazards.show': 'Mostra zone di pericolo',
|
||||
'roadtrip.hazards.current': 'Avvisi attuali',
|
||||
'roadtrip.hazards.note': 'Gli avvisi non indicano strade chiuse. Il percorso non cambia.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Google Mapsのルートをインポート',
|
||||
'roadtrip.import.note': '立ち寄り先を選択した日に追加し、TREKでルートを再計算します。',
|
||||
'roadtrip.import.unresolved': '場所が見つからないため、この立ち寄り先はスキップされます。',
|
||||
'roadtrip.import.day': '日',
|
||||
'roadtrip.hazards.show': '危険地域を表示',
|
||||
'roadtrip.hazards.current': '現在の警報',
|
||||
'roadtrip.hazards.note': '警報は通行止めを意味しません。ルートは変更されません。',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Google Maps 경로 가져오기',
|
||||
'roadtrip.import.note': '경유지를 선택한 날짜에 추가합니다. TREK이 경로를 다시 계산합니다.',
|
||||
'roadtrip.import.unresolved': '위치를 찾을 수 없어 이 경유지를 건너뜁니다.',
|
||||
'roadtrip.import.day': '일',
|
||||
'roadtrip.hazards.show': '위험 지역 표시',
|
||||
'roadtrip.hazards.current': '현재 경보',
|
||||
'roadtrip.hazards.note': '경보는 도로 폐쇄를 의미하지 않습니다. 경로는 변경되지 않습니다.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Google Maps-route importeren',
|
||||
'roadtrip.import.note': 'Stops worden aan de gekozen dag toegevoegd. TREK berekent de route opnieuw.',
|
||||
'roadtrip.import.unresolved': 'Locatie niet gevonden; deze stop wordt overgeslagen.',
|
||||
'roadtrip.import.day': 'Dag',
|
||||
'roadtrip.hazards.show': 'Gevarengebieden tonen',
|
||||
'roadtrip.hazards.current': 'Actuele waarschuwingen',
|
||||
'roadtrip.hazards.note': 'Waarschuwingen zijn geen wegafsluitingen. De route blijft ongewijzigd.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Importuj trasę z Google Maps',
|
||||
'roadtrip.import.note': 'Przystanki zostaną dodane do wybranego dnia. TREK przeliczy trasę.',
|
||||
'roadtrip.import.unresolved': 'Nie znaleziono miejsca; ten przystanek zostanie pominięty.',
|
||||
'roadtrip.import.day': 'Dzień',
|
||||
'roadtrip.hazards.show': 'Pokaż obszary zagrożeń',
|
||||
'roadtrip.hazards.current': 'Aktualne ostrzeżenia',
|
||||
'roadtrip.hazards.note': 'Ostrzeżenia nie oznaczają zamknięcia dróg. Trasa pozostaje bez zmian.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Импорт маршрута Google Maps',
|
||||
'roadtrip.import.note': 'Остановки добавляются в выбранный день. TREK пересчитает маршрут.',
|
||||
'roadtrip.import.unresolved': 'Место не найдено; эта остановка будет пропущена.',
|
||||
'roadtrip.import.day': 'День',
|
||||
'roadtrip.hazards.show': 'Показывать опасные зоны',
|
||||
'roadtrip.hazards.current': 'Текущие предупреждения',
|
||||
'roadtrip.hazards.note': 'Предупреждения не означают закрытие дорог. Маршрут не меняется.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Importera Google Maps-rutt',
|
||||
'roadtrip.import.note': 'Stoppen läggs till på vald dag. TREK beräknar rutten på nytt.',
|
||||
'roadtrip.import.unresolved': 'Platsen hittades inte; stoppet hoppas över.',
|
||||
'roadtrip.import.day': 'Dag',
|
||||
'roadtrip.hazards.show': 'Visa riskområden',
|
||||
'roadtrip.hazards.current': 'Aktuella varningar',
|
||||
'roadtrip.hazards.note': 'Varningar är inte vägavstängningar. Rutten ändras inte.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Google Maps rotasını içe aktar',
|
||||
'roadtrip.import.note': 'Duraklar seçilen güne eklenir. TREK rotayı yeniden hesaplar.',
|
||||
'roadtrip.import.unresolved': 'Konum bulunamadı; bu durak atlanacak.',
|
||||
'roadtrip.import.day': 'Gün',
|
||||
'roadtrip.hazards.show': 'Tehlike bölgelerini göster',
|
||||
'roadtrip.hazards.current': 'Güncel uyarılar',
|
||||
'roadtrip.hazards.note': 'Uyarılar yol kapatmaları değildir. Rota değişmez.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Імпорт маршруту Google Maps',
|
||||
'roadtrip.import.note': 'Зупинки додаються до вибраного дня. TREK перерахує маршрут.',
|
||||
'roadtrip.import.unresolved': 'Місце не знайдено; цю зупинку буде пропущено.',
|
||||
'roadtrip.import.day': 'День',
|
||||
'roadtrip.hazards.show': 'Показувати небезпечні зони',
|
||||
'roadtrip.hazards.current': 'Поточні попередження',
|
||||
'roadtrip.hazards.note': 'Попередження не означають закриття доріг. Маршрут не змінюється.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': 'Nhập tuyến đường Google Maps',
|
||||
'roadtrip.import.note': 'Các điểm dừng được thêm vào ngày đã chọn. TREK tính lại tuyến đường.',
|
||||
'roadtrip.import.unresolved': 'Không tìm thấy vị trí; điểm dừng này sẽ bị bỏ qua.',
|
||||
'roadtrip.import.day': 'Ngày',
|
||||
'roadtrip.hazards.show': 'Hiển thị vùng nguy hiểm',
|
||||
'roadtrip.hazards.current': 'Cảnh báo hiện tại',
|
||||
'roadtrip.hazards.note': 'Cảnh báo không có nghĩa là đường bị đóng. Tuyến đường không thay đổi.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': '匯入 Google Maps 路線',
|
||||
'roadtrip.import.note': '停靠點將新增至所選日期。TREK 將重新計算路線。',
|
||||
'roadtrip.import.unresolved': '找不到位置;將略過此停靠點。',
|
||||
'roadtrip.import.day': '天',
|
||||
'roadtrip.hazards.show': '顯示危險區域',
|
||||
'roadtrip.hazards.current': '目前警報',
|
||||
'roadtrip.hazards.note': '警報不代表道路封閉。路線保持不變。',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { TranslationStrings } from '../types';
|
||||
|
||||
const roadtrip: TranslationStrings = {
|
||||
'roadtrip.import.title': '导入 Google Maps 路线',
|
||||
'roadtrip.import.note': '停靠点将添加到所选日期。TREK 将重新计算路线。',
|
||||
'roadtrip.import.unresolved': '未找到位置;将跳过此停靠点。',
|
||||
'roadtrip.import.day': '天',
|
||||
'roadtrip.hazards.show': '显示危险区域',
|
||||
'roadtrip.hazards.current': '当前警报',
|
||||
'roadtrip.hazards.note': '警报不代表道路封闭。路线保持不变。',
|
||||
|
||||
@@ -79,3 +79,5 @@ export * from './plugins/plugins.schema';
|
||||
export * from './roadtrip/preferences.schema';
|
||||
export * from './roadtrip/hazards.schema';
|
||||
export * from './roadtrip/planning.schema';
|
||||
export * from './roadtrip/search.schema';
|
||||
export * from './roadtrip/google-import.schema';
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { idSchema } from '../common/primitives.schema';
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
export const googleRoutePreviewRequestSchema = z.object({ url: z.string().url().max(12000) });
|
||||
export const googleRouteStopSchema = z.object({
|
||||
name: z.string().min(1).max(200),
|
||||
lat: z.number().min(-90).max(90),
|
||||
lng: z.number().min(-180).max(180),
|
||||
});
|
||||
export const googleRoutePreviewSchema = z.object({
|
||||
stops: z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
lat: z.number().nullable(),
|
||||
lng: z.number().nullable(),
|
||||
}),
|
||||
)
|
||||
.max(30),
|
||||
});
|
||||
export const googleRouteImportSchema = z.object({
|
||||
dayId: idSchema,
|
||||
stops: z.array(googleRouteStopSchema).min(2).max(30),
|
||||
});
|
||||
export type GoogleRouteImport = z.infer<typeof googleRouteImportSchema>;
|
||||
export type GoogleRoutePreview = z.infer<typeof googleRoutePreviewSchema>;
|
||||
@@ -0,0 +1,14 @@
|
||||
import { roadtripSearchAreaSchema } from './search.schema';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('Roadtrip search area', () => {
|
||||
const request = { categories: ['fuel'], bbox: { south: 48, north: 49, west: 10, east: 11 } };
|
||||
it('validates categories and ordered geographic bounds', () => {
|
||||
expect(roadtripSearchAreaSchema.safeParse(request).success).toBe(true);
|
||||
expect(roadtripSearchAreaSchema.safeParse({ ...request, categories: ['unknown'] }).success).toBe(false);
|
||||
expect(roadtripSearchAreaSchema.safeParse({ ...request, bbox: { ...request.bbox, south: 50 } }).success).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
import { roadtripCorridorRequestSchema } from './planning.schema';
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
export const roadtripSearchAreaSchema = z.object({
|
||||
categories: z.array(roadtripCorridorRequestSchema.shape.category).min(1).max(7),
|
||||
bbox: z
|
||||
.object({
|
||||
south: z.number().min(-90).max(90),
|
||||
north: z.number().min(-90).max(90),
|
||||
west: z.number().min(-180).max(180),
|
||||
east: z.number().min(-180).max(180),
|
||||
})
|
||||
.refine((b) => b.south < b.north && b.west < b.east, 'Invalid search area'),
|
||||
lang: z.string().max(20).optional(),
|
||||
});
|
||||
export type RoadtripSearchArea = z.infer<typeof roadtripSearchAreaSchema>;
|
||||
|
||||
export const roadtripSearchPoiSchema = z.object({
|
||||
osm_id: z.string(),
|
||||
name: z.string(),
|
||||
lat: z.number(),
|
||||
lng: z.number(),
|
||||
category: z.string(),
|
||||
poi_type: z.string(),
|
||||
source: z.string(),
|
||||
address: z.string().nullable(),
|
||||
website: z.string().nullable(),
|
||||
phone: z.string().nullable(),
|
||||
opening_hours: z.string().nullable(),
|
||||
cuisine: z.string().nullable(),
|
||||
brand: z.string().nullable().optional(),
|
||||
brand_wikidata: z.string().nullable().optional(),
|
||||
charging: z
|
||||
.object({
|
||||
sockets: z.array(z.object({ type: z.string(), count: z.number().nullable(), kw: z.number().nullable() })),
|
||||
capacity: z.number().nullable(),
|
||||
fee: z.boolean().nullable(),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
rating: z.number().nullable().optional(),
|
||||
pluginId: z.string().optional(),
|
||||
});
|
||||
export const roadtripSearchAreaResponseSchema = z.object({
|
||||
pois: z.array(roadtripSearchPoiSchema),
|
||||
sources: z.array(z.string()),
|
||||
failedSources: z.array(z.string()),
|
||||
truncated: z.boolean(),
|
||||
clamped: z.boolean(),
|
||||
});
|
||||
export type RoadtripSearchAreaResponse = z.infer<typeof roadtripSearchAreaResponseSchema>;
|
||||
Reference in New Issue
Block a user