From ddcd70ebc2fcb9681e26b333cb20f435f775d31f Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 10 Oct 2024 17:12:01 +0200 Subject: [PATCH 01/16] Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: OTP-react-redux/OTP-RR Main UI Translate-URL: https://hosted.weblate.org/projects/otp-react-redux/otp-rr-main-ui/ --- i18n/ru.yml | 71 ++++++++++++++++++++++++++++++++--------------------- i18n/vi.yml | 55 +++++++++++++++++++++++++---------------- 2 files changed, 77 insertions(+), 49 deletions(-) diff --git a/i18n/ru.yml b/i18n/ru.yml index b7a2eedd4..5130b920a 100644 --- a/i18n/ru.yml +++ b/i18n/ru.yml @@ -18,7 +18,8 @@ actions: itineraryCapacityError: >- Невозможно сохранить план. Этот план невозможно сохранить из-за нехватки мест в одном или нескольких транспортных средствах. Измените план поездки. - maxTripRequestsExceeded: Превышено количество запросов на поездку без действительных результатов + maxTripRequestsExceeded: Превышено количество запросов на поездку без действительных + результатов saveItinerariesError: "Не удалось сохранить маршруты: {err}" setDateError: "Ошибка введения данных:" location: @@ -37,9 +38,11 @@ actions: authTokenError: Ошибка получения токена на авторизацию. confirmDeleteMonitoredTrip: Удалить эту поездку? confirmDeletePlace: Удалить это место? - emailVerificationResent: Сообщение с подтверждением адреса электронной почты отправлено повторно. + emailVerificationResent: Сообщение с подтверждением адреса электронной почты отправлено + повторно. genericError: "Произошла ошибка: {err}" - itineraryExistenceCheckFailed: При проверке возможности выбранной поездки произошла ошибка. + itineraryExistenceCheckFailed: При проверке возможности выбранной поездки произошла + ошибка. mustAcceptTermsToSavePlace: >- Примите «Условия использования» (в разделе «Моя учетная запись»), чтобы сохранять местоположения. @@ -99,15 +102,11 @@ common: submitting: Отправка… "yes": Да itineraryDescriptions: - calories: "{calories, number} кал" fareUnknown: Информации о стоимости поездки нет. noItineraryToDisplay: Нет маршрута для отображения. relativeCo2: > {co2} {isMore, select, true {больше } other {меньше} } CO₂, чем при вождении в одиночку - transfers: >- - {transfers, plural, =0 {} one {# пересадка} other {несколько пересадок - (#)}} linkOpensNewWindow: (Открывает новое окно) modes: bicycle_rent: Прокат велосипедов @@ -146,7 +145,6 @@ common: enterStartLocation: Введите место отправления или {mapAction} на карте… tap: коснитесь его time: - departureArrivalTimes: "{startTime, time, short}\_— {endTime, time, short}" duration: aFewSeconds: несколько секунд nDays: "{days} дн." @@ -256,7 +254,6 @@ components: ariaLabel: Навигационная форма ItinerarySummary: itineraryDetails: Сведения о маршруте - minMaxFare: "{minTotalFare}\_— {maxTotalFare}" LocationSearch: enterLocation: Ввести местоположение setDestination: Выбрать место назначения @@ -285,7 +282,8 @@ components: header: Задать параметры поиска NarrativeItinerariesHeader: changeSortDir: Изменить направление сортировки - howToFindResults: Чтобы просмотреть результаты, см. заголовок «Найденные маршруты» ниже. + howToFindResults: Чтобы просмотреть результаты, см. заголовок «Найденные маршруты» + ниже. itinerariesFound: |- {itineraryNum, plural, one {найден # маршрут} @@ -388,7 +386,7 @@ components: TO: Mесто назначения PhoneNumberEditor: changeNumber: Изменить номер - invalidCode: "Введите проверочный код из 6\_цифр." + invalidCode: "Введите проверочный код из 6 цифр." invalidPhone: Введите действительный номер телефона. pending: Ожидание phoneNumberSubmitted: Номер телефона{phoneNumber} был успешно отправлен. @@ -402,7 +400,9 @@ components: подтверждением и мониторингом поездки. Вашим оператором мобильной связи могут взиматься дополнительные пени. verificationCode: "Код подтверждения:" - verificationInstructions: "Откройте приложение для обмена SMS на телефоне и найдите текстовое сообщение с кодом подтверждения. Затем введите код ниже (срок действия кода: 10\_минут).\n" + verificationInstructions: "Откройте приложение для обмена SMS на телефоне и найдите + текстовое сообщение с кодом подтверждения. Затем введите код ниже (срок действия + кода: 10 минут).\n" verified: Подтверждено verify: Подтвердить Place: @@ -498,7 +498,8 @@ components: tooManyTrips: > Можно сохранить не более пяти поездок. Удалите неиспользуемые поездки из раздела сохраненных и попробуйте еще раз. - tripNameAlreadyUsed: У вас уже сохранена поездка с таким именем. Укажите другое имя. + tripNameAlreadyUsed: У вас уже сохранена поездка с таким именем. Укажите другое + имя. tripNameRequired: Укажите имя поездки. SequentialPaneDisplay: stepNumber: Шаг {шаг} из {общее кол-во} @@ -553,9 +554,13 @@ components: defaultContent: Переключить switchLocations: Переключить местоположения TermsOfUsePane: - confirmDeletionPrompt: "Недавние поисковые запросы и\_(или) места сохранены. Отключение сохранения недавних мест и\_(или) поисковых запросов приведет к удалению этих элементов. Продолжить?\n" + confirmDeletionPrompt: "Недавние поисковые запросы и (или) места сохранены. Отключение + сохранения недавних мест и (или) поисковых запросов приведет к удалению этих + элементов. Продолжить?\n" mustAgreeToTerms: Для продолжения примите условия использования. - termsOfServiceStatement: "Я подтверждаю, что мне исполнилось 18\_лет и что я прочитал и принимаю Условия использования планировщика поездок.\n" + termsOfServiceStatement: "Я подтверждаю, что мне исполнилось 18 лет и что я прочитал + и принимаю Условия использования планировщика + поездок.\n" termsOfStorageStatement: > Необязательно: я даю согласие на то, чтобы планировщик поездок хранил архивные данные о моих запланированных поездках с целью улучшения услуг @@ -573,8 +578,10 @@ components: tripIsAvailableOnDaysIndicated: Поездка доступна для указанных выше дней. tripNamePrompt: "Укажите имя поездки:" tripNotAvailableOnDay: "Поездка недоступна для следующих дней: {repeatedDay}" - unsavedChangesExistingTrip: Вы не сохранили поездку. Если вы выйдете, все изменения будут утеряны. - unsavedChangesNewTrip: Вы не сохранили новую поездку. Если вы выйдете, она будет удалена. + unsavedChangesExistingTrip: Вы не сохранили поездку. Если вы выйдете, все изменения + будут утеряны. + unsavedChangesNewTrip: Вы не сохранили новую поездку. Если вы выйдете, она будет + удалена. TripNotificationsPane: advancedSettings: Расширенные настройки altRouteRecommended: Рекомендуется использовать пересадку или альтернативный маршрут @@ -585,7 +592,7 @@ components: monitorThisTrip: "Мониторинг данной поездки до ее начала:" notificationsTurnedOff: Уведомления отключены в настройках вашей учетной записи. notifyViaChannelWhen: "Использовать канал «{channel}» для уведомлений, когда:" - oneHour: "1\_ч" + oneHour: "1 ч" realtimeAlertFlagged: Для моего пути есть предупреждение в режиме реального времени timeBefore: "{time} до" TripStatus: @@ -644,14 +651,16 @@ components: реальном времени запустится в {monitoringStart, time, short}.) tripStartIsDelayed: Начало поездки откладывается на {duration}! tripStartIsEarly: Начало поездки произойдет на {duration} раньше ожидаемого! - tripStartsSoonNoUpdates: Поездка скоро начнется (обновления в реальном времени недоступны). + tripStartsSoonNoUpdates: Поездка скоро начнется (обновления в реальном времени + недоступны). tripStartsSoonOnTime: Поездка скоро начнется. Без задержек. TripSummary: arriveAt: "Прибытие в " leaveAt: "Оставить " TripSummaryPane: happensOnDays: "Проходит в такие дни: {days}" - notifications: за {leadTimeInMinutes} мин до запланированного времени отправления + notifications: за {leadTimeInMinutes} мин до запланированного времени + отправления notificationsDisabled: "Уведомления: отключены" TripTools: copyLink: Скопировать ссылку @@ -691,17 +700,23 @@ components: storeTripHistory: Сохранять историю поездок updating: Обновляется UserSettings: - confirmDeletion: "Недавние поисковые запросы и\_(или) места сохранены. Отключение сохранения недавних мест и\_(или) поисковых запросов приведет к удалению этих элементов. Продолжить?" + confirmDeletion: "Недавние поисковые запросы и (или) места сохранены. Отключение + сохранения недавних мест и (или) поисковых запросов приведет к удалению этих + элементов. Продолжить?" favoriteStops: Избранные остановки myPreferences: Мои параметры mySavedPlaces: Мои сохраненные места (изменить) noFavoriteStops: Избранные остановки recentPlaces: Недавние места - recentSearchSummary: "Режим «{mode}». {from}\_— {to}" + recentSearchSummary: "Режим «{mode}». {from} — {to}" recentSearches: Недавние поисковые запросы - rememberSearches: "Сохранить недавние места\_/ поисковые запросы?" + rememberSearches: "Сохранить недавние места / поисковые запросы?" stopId: "Идентификатор остановки: {stopId}" - storageDisclaimer: "Все сохраненные параметры, места и настройки будут храниться в локальном хранилище браузера. TriMet не получит доступ к данным о вашем доме, месте работы или другим местоположениям. В любой момент вы можете отключить сохранение недавних мест\_/ поисковых запросов и очистить список местоположений дома/работы, а также избранных остановок.\n" + storageDisclaimer: "Все сохраненные параметры, места и настройки будут храниться + в локальном хранилище браузера. TriMet не получит доступ к данным о вашем доме, + месте работы или другим местоположениям. В любой момент вы можете отключить + сохранение недавних мест / поисковых запросов и очистить список местоположений + дома/работы, а также избранных остановок.\n" UserTripSettings: forgetOptions: Удалить варианты rememberOptions: Сохранить варианты поездки @@ -723,12 +738,12 @@ components: prompt: Куда вы хотите отправиться? config: accessModes: - bicycle: "Общественный транспорт\_+\_личный велосипед" - bicycle_rent: "Общественный транспорт\_+\_прокат велосипеда" + bicycle: "Общественный транспорт + личный велосипед" + bicycle_rent: "Общественный транспорт + прокат велосипеда" car_hail: Заказная поездка car_park: Парковочное место - micromobility: "Общественный транспорт\_+\_личный самокат" - micromobility_rent: "Общественный транспорт\_+\_прокат электросамоката" + micromobility: "Общественный транспорт + личный самокат" + micromobility_rent: "Общественный транспорт + прокат электросамоката" bicycleModes: bicycle: Личный велосипед bicycle_rent: Прокат велосипедов diff --git a/i18n/vi.yml b/i18n/vi.yml index 719ee0898..dd44b335f 100644 --- a/i18n/vi.yml +++ b/i18n/vi.yml @@ -5,7 +5,8 @@ actions: callQuerySaveError: "Lỗi khi lưu trữ các truy vấn cuộc gọi: {err}" callSaveError: "Không thể lưu cuộc gọi: {err}" checkSessionError: "Lỗi khi thiết lập phiên ủy quyền: {err}" - couldNotFindCallError: Không thể tìm thấy cuộc gọi. Đang hủy yêu cầu lưu truy vấn. + couldNotFindCallError: Không thể tìm thấy cuộc gọi. Đang hủy yêu cầu lưu truy + vấn. fetchCallsError: "Lỗi khi tìm nạp cuộc gọi: {err}" queryFetchError: "Lỗi khi tìm nạp các truy vấn: {err}" fieldTrip: @@ -28,7 +29,8 @@ actions: Không thể lưu kế hoạch chuyến đi: Không thể lưu kế hoạch chuyến đi này do thiếu sức chứa trên một hoặc nhiều xe. Vui lòng lên kế hoạch lại chuyến đi của bạn. - maxTripRequestsExceeded: Đã vượt quá số lượng yêu cầu chuyến đi mà không có kết quả hợp lệ + maxTripRequestsExceeded: Đã vượt quá số lượng yêu cầu chuyến đi mà không có kết + quả hợp lệ saveItinerariesError: "Không lưu được hành trình: {err}" setDateError: "Lỗi khi cài đặt ngày:" setGroupSizeError: "Lỗi khi cài đặt kích thước nhóm:" @@ -40,7 +42,8 @@ actions: Để sử dụng địa điểm hiện tại của mình, quý vị hãy cho phép sử dụng vị trí trong trình duyệt và tải lại trang này. - geolocationNotSupportedError: Định vị địa lý không được hỗ trợ bởi trình duyệt của bạn + geolocationNotSupportedError: Định vị địa lý không được hỗ trợ bởi trình duyệt + của bạn unknownPositionError: Lỗi không xác định khi tìm vị trí userDeniedPermission: Người dùng từ chối cấp quyền map: @@ -52,7 +55,8 @@ actions: confirmDeletePlace: Bạn có muốn loại bỏ nơi này không? emailVerificationResent: Thông báo xác minh email đã được gửi lại. genericError: "Phát sinh lỗi: {err}" - itineraryExistenceCheckFailed: Lỗi kiểm tra xem chuyến đi được chọn của bạn là có thể. + itineraryExistenceCheckFailed: Lỗi kiểm tra xem chuyến đi được chọn của bạn là + có thể. mustAcceptTermsToSavePlace: >- Vui lòng chấp nhận Điều Khoản Sử Dụng (trong phần Tài Khoản Của Tôi) để lưu lại địa điểm. @@ -112,12 +116,10 @@ common: submitting: Đang gửi… "yes": Đúng itineraryDescriptions: - calories: "{calories, number} calo" fareUnknown: Không có thông tin giá vé noItineraryToDisplay: Không có hành trình để hiển thị. relativeCo2: | {co2} CO₂ {isMore, select, true {nhiều} other {ít} } hơn so với xe hơi - transfers: "{transfers, plural, =0 {} other {# chuyển}}" linkOpensNewWindow: (Mở khoảng thời gian mới) modes: bicycle_rent: Chia sẻ xe đạp @@ -156,7 +158,6 @@ common: enterStartLocation: Nhập vị trí bắt đầu hoặc {mapAction} vào bản đồ… tap: chạm time: - departureArrivalTimes: "{startTime, time, short}—{endTime, time, short}" duration: aFewSeconds: vài giây nDays: "{days} ngày" @@ -168,12 +169,14 @@ common: {} other {# giây}} components: A11yPrefs: - accessibilityRoutingByDefault: Thích những chuyến đi có thể truy cập theo mặc định + accessibilityRoutingByDefault: Thích những chuyến đi có thể truy cập theo mặc + định AccountSetupFinishPane: message: Bạn đã sẵn sàng để bắt đầu lên kế hoạch cho các chuyến đi của bạn. AddPlaceButton: addPlace: Thêm địa điểm - needOriginDestination: Xác định nguồn gốc hoặc đích đến để thêm các địa điểm trung gian + needOriginDestination: Xác định nguồn gốc hoặc đích đến để thêm các địa điểm trung + gian tooManyPlaces: Địa điểm trung gian tối đa đạt được AdvancedOptions: bannedRoutes: Chọn các tuyến đường bị cấm… @@ -259,14 +262,14 @@ components: editPlaceGeneric: Chỉnh sửa vị trí invalidAddress: Vui lòng cài đặt một vị trí cho nơi này. invalidName: Vui lòng nhập tên cho nơi này. - nameAlreadyUsed: Bạn đã sử dụng tên này cho một nơi khác. Vui lòng nhập một tên khác. + nameAlreadyUsed: Bạn đã sử dụng tên này cho một nơi khác. Vui lòng nhập một tên + khác. placeNotFound: Không tìm thấy địa điểm placeNotFoundDescription: Xin lỗi, địa điểm được yêu cầu không được tìm thấy. FormNavigationButtons: ariaLabel: Điều hướng hình thức ItinerarySummary: itineraryDetails: Chi tiết hành trình - minMaxFare: "{minTotalFare} - {maxTotalFare}" LocationSearch: enterLocation: Nhập vị trí setDestination: Chọn điểm đến @@ -335,8 +338,10 @@ components: description: Nội dung bạn yêu cầu không có sẵn. header: Không tìm thấy nội dung NotificationPrefsPane: - devicesRegistered: "{count, plural, one {# device} other {# devices}} đã đăng ký" - noDeviceForPush: Đăng ký thiết bị của quý vị bằng ứng dụng di động để nhận thông báo đẩy. + devicesRegistered: "{count, plural, one {# device} other {# devices}} đã đăng + ký" + noDeviceForPush: Đăng ký thiết bị của quý vị bằng ứng dụng di động để nhận thông + báo đẩy. notificationChannelPrompt: "Nhận thông báo về các chuyến đi đã lưu bằng:" OTP2ErrorRenderer: LOCATION_NOT_FOUND: @@ -577,16 +582,21 @@ components: travelingAt: di chuyển với tốc độ {milesPerHour} vehicleName: Phương tiện giao thông {vehicleNumber} TripBasicsPane: - checkingItineraryExistence: Kiểm tra sự tồn tại của hành trình cho mỗi ngày trong tuần… + checkingItineraryExistence: Kiểm tra sự tồn tại của hành trình cho mỗi ngày trong + tuần… tripDaysPrompt: Bạn thực hiện chuyến đi này vào những ngày nào? - tripIsAvailableOnDaysIndicated: Chuyến đi của bạn có sẵn vào những ngày trong tuần như đã nêu ở trên. + tripIsAvailableOnDaysIndicated: Chuyến đi của bạn có sẵn vào những ngày trong + tuần như đã nêu ở trên. tripNamePrompt: "Vui lòng cung cấp tên cho chuyến đi này:" tripNotAvailableOnDay: Chuyến đi không có sẵn vào {repeatedDay} - unsavedChangesExistingTrip: Bạn chưa lưu chuyến đi của mình. Nếu bạn rời đi, những thay đổi sẽ bị mất. - unsavedChangesNewTrip: Bạn chưa lưu chuyến đi mới của mình. Nếu bạn rời đi, nó sẽ bị mất. + unsavedChangesExistingTrip: Bạn chưa lưu chuyến đi của mình. Nếu bạn rời đi, những + thay đổi sẽ bị mất. + unsavedChangesNewTrip: Bạn chưa lưu chuyến đi mới của mình. Nếu bạn rời đi, nó + sẽ bị mất. TripNotificationsPane: advancedSettings: Cài đặt nâng cao - altRouteRecommended: Một tuyến đường hoặc điểm trung chuyển thay thế được khuyến nghị + altRouteRecommended: Một tuyến đường hoặc điểm trung chuyển thay thế được khuyến + nghị delaysAboveThreshold: Có sự chậm trễ hoặc gián đoạn của hơn howToReceiveAlerts: > Để nhận thông báo cho các chuyến đi đã lưu của bạn, bật thông báo trong @@ -595,7 +605,8 @@ components: notificationsTurnedOff: Thông báo được tắt cho tài khoản của bạn. notifyViaChannelWhen: "Thông báo cho tôi qua {channel} khi:" oneHour: 1 tiếng - realtimeAlertFlagged: Có một cảnh báo thời gian thực được gắn cờ trên hành trình của tôi + realtimeAlertFlagged: Có một cảnh báo thời gian thực được gắn cờ trên hành trình + của tôi timeBefore: "{time} trước" TripStatus: alerts: "{alerts, plural, one {# cảnh báo!} other {# cảnh báo!}}" @@ -608,7 +619,8 @@ components: earlyHeading: >- Chuyến đi đang diễn ra và sẽ đến sớm hơn {formattedDuration} so với dự kiến! - noDataHeading: Chuyến đi đang được tiến hành (không có cập nhật thời gian thực có sẵn). + noDataHeading: Chuyến đi đang được tiến hành (không có cập nhật thời gian thực + có sẵn). onTimeHeading: Chuyến đi đang được tiến hành và đúng giờ. base: lastCheckedDefaultText: Thời gian được kiểm tra lần cuối không xác định @@ -651,7 +663,8 @@ components: tripStartIsEarly: >- Thời gian bắt đầu chuyến đi đang diễn ra sớm hơn {duration} so với dự kiến! - tripStartsSoonNoUpdates: Chuyến đi đang bắt đầu sớm (không có cập nhật về thời gian thực). + tripStartsSoonNoUpdates: Chuyến đi đang bắt đầu sớm (không có cập nhật về thời + gian thực). tripStartsSoonOnTime: Chuyến đi đang bắt đầu sớm và sắp đúng giờ. TripSummary: arriveAt: "Đến nơi " From deaa9a5d52061310568ecdb4512d002f9e395e6b Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Thu, 10 Oct 2024 15:43:18 +0000 Subject: [PATCH 02/16] Translated using Weblate (Spanish) Currently translated at 100.0% (553 of 553 strings) Translation: OTP-react-redux/OTP-RR Main UI Translate-URL: https://hosted.weblate.org/projects/otp-react-redux/otp-rr-main-ui/es/ --- i18n/es.yml | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/i18n/es.yml b/i18n/es.yml index 2a25daa1a..6675da344 100644 --- a/i18n/es.yml +++ b/i18n/es.yml @@ -30,7 +30,8 @@ actions: No se puede guardar el plan: este plan no se pudo guardar debido a la falta de capacidad en uno o más vehículos. Por favor, vuelva a planificar su viaje. - maxTripRequestsExceeded: Número de solicitudes de viaje superadas sin resultados válidos + maxTripRequestsExceeded: Número de solicitudes de viaje superadas sin resultados + válidos saveItinerariesError: "No se pudieron guardar los itinerarios: {err}" setDateError: "Error al establecer la fecha:" setGroupSizeError: "No se pudo establecer el tamaño del grupo:" @@ -52,10 +53,13 @@ actions: authTokenError: Error al obtener un token de autorización. confirmDeleteMonitoredTrip: ¿Desea eliminar este viaje? confirmDeletePlace: ¿Quiere eliminar este lugar? - emailVerificationResent: El mensaje de verificación de correo electrónico ha sido reenviado. + emailVerificationResent: El mensaje de verificación de correo electrónico ha sido + reenviado. genericError: "Se ha encontrado un error: {err}" - itineraryExistenceCheckFailed: Comprobación de errores para ver si el viaje seleccionado es posible. - mustAcceptTermsToSavePlace: Acepte los Términos de uso (en Mi Cuenta) para guardar las ubicaciones. + itineraryExistenceCheckFailed: Comprobación de errores para ver si el viaje seleccionado + es posible. + mustAcceptTermsToSavePlace: Acepte los Términos de uso (en Mi Cuenta) para guardar + las ubicaciones. mustBeLoggedInToSavePlace: Por favor, inicia la sesión para guardar las ubicaciones. placeRemembered: La configuración de este lugar se ha guardado. preferencesSaved: Sus preferencias se han guardado. @@ -112,13 +116,12 @@ common: submitting: Enviando… "yes": Sí itineraryDescriptions: - calories: "{calories, number} kcal" fareUnknown: No hay información de las tarifas noItineraryToDisplay: No hay itinerario que mostrar. relativeCo2: > {co2} de CO₂ en {isMore, select, true {más} other {menos} } que conducir solo - transfers: "{transfers, plural, =0 {} one {# transferencia} other {# transferencias}}" + timeStartEnd: '{start} – {end}' linkOpensNewWindow: (Abre una nueva ventana) modes: bicycle_rent: Compartir bicicleta @@ -157,7 +160,6 @@ common: enterStartLocation: Introduzca la ubicación de inicio o {mapAction} en el mapa… tap: toque time: - departureArrivalTimes: "{startTime, time, short}—{endTime, time, short}" duration: aFewSeconds: unos segundos nDays: "{days, plural, =1 {un día} other {# días}}" @@ -201,6 +203,13 @@ components: BatchSearchScreen: header: Planifique su viaje modeSelectorLabel: Seleccione un modo de desplazamiento + moreOptions: Más opciones + saveAndReturn: Guardar y volver + saved: Guardado + tripOptions: Opciones de ruta + submodeSelectorLabel: Seleccionar modos y submodos de desplazamiento + advancedHeader: Ajustes avanzados + modeOptions: Más opciones BatchSettings: destination: destino invalidModeSelection: >- @@ -208,7 +217,8 @@ components: a incluir el transporte publico en la selección de modos. origin: origen planTripTooltip: Planificar viaje - validationMessage: "Por favor, defina los siguientes campos para planificar un viaje: {issues}" + validationMessage: "Por favor, defina los siguientes campos para planificar un + viaje: {issues}" BeforeSignInScreen: mainTitle: Iniciando sesión message: > @@ -267,7 +277,6 @@ components: ariaLabel: Navegar por los formularios ItinerarySummary: itineraryDetails: Detalles del itinerario - minMaxFare: "{minTotalFare} - {maxTotalFare}" LocationSearch: enterLocation: Introduzca la ubicación setDestination: Establecer el destino @@ -281,6 +290,7 @@ components: shared-vehicles: Vehículos compartidos stops: Paradas de tránsito streets: Calles + stations: Estaciones de transporte MapillaryFrame: title: Imágenes de la calle MetroUI: @@ -292,6 +302,7 @@ components: originallyScheduledTime: (originalmente {originalTime}) singleModeItineraryDescription: Viaja {time} {mode} timeWalking: "{time} caminando" + itinerarySummary: Desde {stopName} | {cost} MobileOptions: header: Configurar las opciones de búsqueda MobilityProfile: @@ -370,6 +381,7 @@ components: nearbyListIntro: Lista de {count} entidades cercanas. nothingNearby: No ubicaciónes cercanas. spacesAvailable: "{spacesAvailable} espacios libres disponibles" + headsign: '{destination}' NewAccountWizard: createNewAccount: Crear una nueva cuenta finish: ¡Configuración de la cuenta completa! @@ -549,6 +561,7 @@ components: Otro viaje guardado ya utiliza este nombre. Por favor, elija un nombre diferente. tripNameRequired: Por favor, introduzca el nombre del viaje. + selectAtLeastOneDay: Por favor, seleccione al menos un día para realizar el seguimiento. SequentialPaneDisplay: stepNumber: Paso {step} de {total} SessionTimeout: @@ -558,7 +571,8 @@ components: header: ¡La sesión está a punto de terminar! keepSession: Continuar sesión SimpleRealtimeAnnotation: - usingRealtimeInfo: Este viaje utiliza información de tráfico y retrasos en tiempo real + usingRealtimeInfo: Este viaje utiliza información de tráfico y retrasos en tiempo + real StackedPaneDisplay: savePreferences: Guardar preferencias StopScheduleTable: @@ -620,15 +634,18 @@ components: travelingAt: Viajando a {milesPerHour} vehicleName: Vehículo {vehicleNumber} TripBasicsPane: - checkingItineraryExistence: Comprobación de la existencia de itinerarios para cada día de la semana… + checkingItineraryExistence: Comprobación de la existencia de itinerarios para + cada día de la semana… tripDaysPrompt: ¿Qué días hace este viaje? - tripIsAvailableOnDaysIndicated: Su viaje está disponible en los días de la semana indicados anteriormente. + tripIsAvailableOnDaysIndicated: Su viaje está disponible en los días de la semana + indicados anteriormente. tripNamePrompt: "Por favor, indique un nombre para este viaje:" tripNotAvailableOnDay: El viaje no está disponible el {repeatedDay} unsavedChangesExistingTrip: >- Todavía no ha guardado su viaje. Si abandona la página, los cambios se perderán. - unsavedChangesNewTrip: Todavía no ha guardado su nuevo viaje. Si abandona la página, se perderá. + unsavedChangesNewTrip: Todavía no ha guardado su nuevo viaje. Si abandona la página, + se perderá. TripNotificationsPane: advancedSettings: Configuración avanzada altRouteRecommended: Se recomienda una ruta alternativa o un punto de transferencia @@ -694,11 +711,15 @@ components: El viaje debe comenzar a las {tripStart, time, short}. (El seguimiento en tiempo real comenzará a las {monitoringStart, time, short}.) tripStartIsDelayed: ¡La hora de inicio del viaje se retrasa {duration}! - tripStartIsEarly: ¡La hora de inicio del viaje se produce {duration} antes de lo previsto! + tripStartIsEarly: ¡La hora de inicio del viaje se produce {duration} antes de + lo previsto! tripStartsSoonNoUpdates: >- El viaje comienza pronto (no hay actualizaciones disponibles en tiempo real). tripStartsSoonOnTime: El viaje comienza pronto y es más o menos puntual. + past: + heading: Viaje realizado + description: Un viaje que ocurrió el pasado. TripSummary: arriveAt: "Llegue a las " leaveAt: "Salida a las " From 3f6d69d72d9592ab5e64598844430696d0ee9c0a Mon Sep 17 00:00:00 2001 From: Binh Dam Date: Thu, 10 Oct 2024 15:14:45 +0000 Subject: [PATCH 03/16] Translated using Weblate (Spanish) Currently translated at 100.0% (553 of 553 strings) Translation: OTP-react-redux/OTP-RR Main UI Translate-URL: https://hosted.weblate.org/projects/otp-react-redux/otp-rr-main-ui/es/ --- i18n/es.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i18n/es.yml b/i18n/es.yml index 6675da344..9ba66b675 100644 --- a/i18n/es.yml +++ b/i18n/es.yml @@ -646,6 +646,8 @@ components: perderán. unsavedChangesNewTrip: Todavía no ha guardado su nuevo viaje. Si abandona la página, se perderá. + onlyOnDate: Solo el {date, date, ::eeeee yyyyMMdd} + recurringEachWeek: En ciertos días de cada semana TripNotificationsPane: advancedSettings: Configuración avanzada altRouteRecommended: Se recomienda una ruta alternativa o un punto de transferencia From 13c464f03d6f7747275056c4d7ce9327b5134c25 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Thu, 10 Oct 2024 15:44:32 +0000 Subject: [PATCH 04/16] Translated using Weblate (Spanish) Currently translated at 100.0% (553 of 553 strings) Translation: OTP-react-redux/OTP-RR Main UI Translate-URL: https://hosted.weblate.org/projects/otp-react-redux/otp-rr-main-ui/es/ --- i18n/es.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/es.yml b/i18n/es.yml index 9ba66b675..c8059863b 100644 --- a/i18n/es.yml +++ b/i18n/es.yml @@ -647,7 +647,7 @@ components: unsavedChangesNewTrip: Todavía no ha guardado su nuevo viaje. Si abandona la página, se perderá. onlyOnDate: Solo el {date, date, ::eeeee yyyyMMdd} - recurringEachWeek: En ciertos días de cada semana + recurringEachWeek: Algunos días de la semana TripNotificationsPane: advancedSettings: Configuración avanzada altRouteRecommended: Se recomienda una ruta alternativa o un punto de transferencia From 973aad8fc9de424e5aedcec43271972882ba7272 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Fri, 18 Oct 2024 17:33:51 +0000 Subject: [PATCH 05/16] Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: OTP-react-redux/OTP-RR Main UI Translate-URL: https://hosted.weblate.org/projects/otp-react-redux/otp-rr-main-ui/ --- i18n/ko.yml | 10 ++++------ i18n/tl.yml | 28 ++++++++++++++++------------ i18n/zh_Hans.yml | 4 ---- i18n/zh_Hant.yml | 4 ---- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/i18n/ko.yml b/i18n/ko.yml index e333e7e62..6b2288763 100644 --- a/i18n/ko.yml +++ b/i18n/ko.yml @@ -22,7 +22,8 @@ actions: fetchFieldTripsError: "트립을 가져오는 중에 오류가 발생했습니다: {err}" fetchTripsForDateError: "필트 트립 날짜에 대한 트립을 가져오는 중에 오류가 발생했습니다: {err}" incompatibleTripDateError: 계획한 트립 날짜({tripDate})가 요청한 트립 날짜({requestDate})가 아닙니다 - itineraryCapacityError: "플랜을 저장할 수 없습니다: 하나 이상의 차량의 용량이 부족하여 이 플랜을 저장할 수 없습니다. 트립을 다시 계획하세요." + itineraryCapacityError: "플랜을 저장할 수 없습니다: 하나 이상의 차량의 용량이 부족하여 이 플랜을 저장할 수 없습니다. + 트립을 다시 계획하세요." maxTripRequestsExceeded: 유효한 결과없이 초과된 트립 요청의 개수 saveItinerariesError: "트립을 저장하는 데 실패했습니다: {err}" setDateError: "날짜를 설정하는 중에 오류가 발생했습니다:" @@ -99,12 +100,10 @@ common: submitting: 제출 중… "yes": 예 itineraryDescriptions: - calories: "{calories, number} 칼로리" fareUnknown: 운임 정보 없음 noItineraryToDisplay: 표시할 일정이 없습니다. relativeCo2: | {co2} CO₂ 를 자동차보다 {isMore, select, true {더} other {덜} } 사용합니다 - transfers: "{transfers, plural, =0 {} other {# 전송}}" linkOpensNewWindow: (새 창 열림) modes: bicycle_rent: 공유자전거 @@ -143,7 +142,6 @@ common: enterStartLocation: 시작 위치 또는 {mapAction}을(를) 지도에 입력하십시오… tap: 클릭 time: - departureArrivalTimes: "{startTime, time, short}—{endTime, time, short}" duration: aFewSeconds: 몇 초 nDays: "{days} 일" @@ -244,7 +242,6 @@ components: ariaLabel: 내비게이션 양식 ItinerarySummary: itineraryDetails: 여정 세부 정보 - minMaxFare: "{minTotalFare} - {maxTotalFare}" LocationSearch: enterLocation: 위치 입력 setDestination: 목적지 선택 @@ -685,5 +682,6 @@ util: networkUnavailable: 현재 {network} 네트워크를 사용할 수 없습니다. noTripFound: 트립을 찾을 수 없습니다. noTripFoundForMode: "{modes}의 트립을 찾을 수 없습니다." - noTripFoundReason: 지정된 최대 거리 내 또는 지정된 시간에 대중 교통 서비스가 없거나, 출발지 또는 도착지가 안전하게 접근가능하지 못할 수 있습니다. + noTripFoundReason: 지정된 최대 거리 내 또는 지정된 시간에 대중 교통 서비스가 없거나, 출발지 또는 도착지가 안전하게 접근가능하지 + 못할 수 있습니다. noTripFoundWithReason: "{noTripFound} {reason}" diff --git a/i18n/tl.yml b/i18n/tl.yml index d1e65084a..87e851dce 100644 --- a/i18n/tl.yml +++ b/i18n/tl.yml @@ -45,7 +45,8 @@ actions: confirmDeletePlace: Gusto mo bang alisin ang lugar na ito? emailVerificationResent: Ipinadala ulit ang mensahe ng pag-verify sa email. genericError: "Nagka-error: {err}" - itineraryExistenceCheckFailed: Nagka-error sa pagtingin kung posible ang napili mong biyahe. + itineraryExistenceCheckFailed: Nagka-error sa pagtingin kung posible ang napili + mong biyahe. mustAcceptTermsToSavePlace: >- Pakitanggap ang Mga Tuntunin ng Paggamit (sa ilalim ng Aking Account) para mag-save ng mga lokasyon. @@ -106,13 +107,11 @@ common: submitting: Isinusumite… "yes": Oo itineraryDescriptions: - calories: "{calories, number} Cal" fareUnknown: Walang impormasyon sa pamasahe noItineraryToDisplay: Walang ipapakitang itinerary. relativeCo2: > {co2} {isMore, select, true {mas maraming} other {mas kaunting} } CO₂ kaysa magmaneho nang mag-isa - transfers: "{transfers, plural, =0 {} one {# transfer} other {# transfers}}" linkOpensNewWindow: (Magbubukas sa bagong window) modes: bicycle_rent: Bikeshare @@ -151,7 +150,6 @@ common: enterStartLocation: Ilagay ang lokasyon ng pagsisimula o {mapAction} sa mapa… tap: tap time: - departureArrivalTimes: "{startTime, time, short}—{endTime, time, short}" duration: aFewSeconds: a few seconds nDays: "{days, plural, =1 {one day} other {# days}}" @@ -204,7 +202,8 @@ components: ang pampublikong transportasyon sa pagpili mo ng mode. origin: pinagmulan planTripTooltip: Planuhin ang biyahe - validationMessage: "Ilarawan ang mga sumusunod na field para makapagplano ng biyahe: {issues}" + validationMessage: "Ilarawan ang mga sumusunod na field para makapagplano ng biyahe: + {issues}" BeforeSignInScreen: mainTitle: Sina-sign in ka message: > @@ -263,7 +262,6 @@ components: ariaLabel: Pag-navigate sa form ItinerarySummary: itineraryDetails: Mga detalye ng itinerary - minMaxFare: "{minTotalFare} - {maxTotalFare}" LocationSearch: enterLocation: Ilagay ang lokasyon setDestination: Itakda ang Patutunguhan @@ -397,7 +395,8 @@ components: invalidPhone: Maglagay ng valid na numero ng telepono. pending: Nakabinbin phoneNumberSubmitted: Matagumpay na naisumite ang numero ng teleponong {phoneNumber}. - phoneNumberVerified: Matagumpay na na-verify ang numero ng teleponong {phoneNumber} . + phoneNumberVerified: Matagumpay na na-verify ang numero ng teleponong {phoneNumber} + . placeholder: Ilagay ang numero ng iyong telepono prompt: "Ilagay ang numero ng iyong telepono para sa mga SMS na notification:" requestNewCode: Humiling ng bagong code @@ -583,9 +582,11 @@ components: travelingAt: Bumibiyahe nang {milesPerHour} vehicleName: Sasakyan {vehicleNumber} TripBasicsPane: - checkingItineraryExistence: Tinitingnan kung may itinerary para sa bawat araw ng linggo... + checkingItineraryExistence: Tinitingnan kung may itinerary para sa bawat araw + ng linggo... tripDaysPrompt: Anong mga araw mo ginagawa ang biyaheng ito? - tripIsAvailableOnDaysIndicated: Available ang iyong biyahe sa mga araw ng linggo na nakasaad sa itaas. + tripIsAvailableOnDaysIndicated: Available ang iyong biyahe sa mga araw ng linggo + na nakasaad sa itaas. tripNamePrompt: "Pangalanan ang biyaheng ito:" tripNotAvailableOnDay: Hindi available ang biyahe sa {repeatedDay} unsavedChangesExistingTrip: >- @@ -630,7 +631,8 @@ components: unknownState: Hindi Alam ang Status ng Biyahe untogglePause: Ipagpatuloy inactive: - description: Ipagpatuloy ang pagsubaybay sa biyahe para makita ang updated na status + description: Ipagpatuloy ang pagsubaybay sa biyahe para makita ang updated na + status heading: Naka-pause ang pagsubaybay sa biyahe nextTripNotPossible: description: > @@ -649,7 +651,8 @@ components: description: Hinihintay na makalkula ang biyahe. heading: Hindi pa nakakalkula ang biyahe snoozed: - description: I-unsnooze ang pagsubaybay sa biyahe para makita ang updated na status. + description: I-unsnooze ang pagsubaybay sa biyahe para makita ang updated na + status. heading: Naka-snooze ang pagsubaybay sa biyahe ngayong araw upcoming: nextTripBegins: >- @@ -659,7 +662,8 @@ components: Magsisimula ang biyahe nang {tripStart, time, short}. (Magsisimula ang realtime na pagsubaybay nang {monitoringStart, time, short}.) tripStartIsDelayed: Naantala ang oras ng pagsisimula ng biyahe nang {duration}! - tripStartIsEarly: Nagsisimula na ang biyahe {duration} na mas maaga kaysa sa inaasahan! + tripStartIsEarly: Nagsisimula na ang biyahe {duration} na mas maaga kaysa sa + inaasahan! tripStartsSoonNoUpdates: >- Malapit nang magsimula ang biyahe (walang realtime na update na available). diff --git a/i18n/zh_Hans.yml b/i18n/zh_Hans.yml index 47464fc2c..1458db732 100644 --- a/i18n/zh_Hans.yml +++ b/i18n/zh_Hans.yml @@ -99,12 +99,10 @@ common: submitting: 正在提交… "yes": 是 itineraryDescriptions: - calories: "{calories, number} 大卡" fareUnknown: 无票价信息 noItineraryToDisplay: 没有显示行程. relativeCo2: | {co2} {isMore, select, true {更多} other {更少} } CO₂ 比单独驾车 - transfers: "{transfers, plural, =0 {} other {# 换乘}}" linkOpensNewWindow: (打开新窗口) modes: bicycle_rent: 共享单车 @@ -143,7 +141,6 @@ common: enterStartLocation: 输入出发地点或{mapAction}地图… tap: 点击 time: - departureArrivalTimes: "{startTime, time, short}—{endTime, time, short}" duration: aFewSeconds: 几秒钟 nDays: "{days} 天" @@ -244,7 +241,6 @@ components: ariaLabel: 表格导航 ItinerarySummary: itineraryDetails: 行程详情 - minMaxFare: "{minTotalFare} - {maxTotalFare}" LocationSearch: enterLocation: 输入位置 setDestination: 设置目的地 diff --git a/i18n/zh_Hant.yml b/i18n/zh_Hant.yml index e625d04c7..b94f45d0a 100644 --- a/i18n/zh_Hant.yml +++ b/i18n/zh_Hant.yml @@ -99,12 +99,10 @@ common: submitting: 正在提交… "yes": 是 itineraryDescriptions: - calories: "{calories, number}卡" fareUnknown: 無票價資訊 noItineraryToDisplay: 沒有預定行程可顯示。 relativeCo2: | {co2}比單獨開車排放的CO₂{isMore, select, true {要多} other {少}} - transfers: "{transfers}次轉乘" linkOpensNewWindow: (開啟新視窗) modes: bicycle_rent: 自行車共享 @@ -143,7 +141,6 @@ common: enterStartLocation: 輸入開始位置或{mapAction} 地圖…… tap: 輕觸 time: - departureArrivalTimes: "{startTime, time, short}—{endTime, time, short}" duration: aFewSeconds: 幾秒鐘 nDays: "{days}天" @@ -244,7 +241,6 @@ components: ariaLabel: 表單導航 ItinerarySummary: itineraryDetails: 路線詳細資訊 - minMaxFare: "{minTotalFare} - {maxTotalFare}" LocationSearch: enterLocation: 輸入位置 setDestination: 設定目的地 From aca5acffd21824843d4bcad727a258762c5caa81 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Fri, 18 Oct 2024 17:58:09 +0000 Subject: [PATCH 06/16] Translated using Weblate (Spanish) Currently translated at 100.0% (554 of 554 strings) Translation: OTP-react-redux/OTP-RR Main UI Translate-URL: https://hosted.weblate.org/projects/otp-react-redux/otp-rr-main-ui/es/ --- i18n/es.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i18n/es.yml b/i18n/es.yml index c8059863b..7d9dbc970 100644 --- a/i18n/es.yml +++ b/i18n/es.yml @@ -816,6 +816,8 @@ components: switcher: Botón de cambio WelcomeScreen: prompt: ¿A donde quiere ir? + TripPreviewLayout: + previewTrip: Vista previa del viaje config: accessModes: bicycle: Tránsito + Bicicleta Personal From 05a28452d8419625853ec7d7c74aaef33ed6660d Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Fri, 22 Nov 2024 20:04:21 +0000 Subject: [PATCH 07/16] Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: OTP-react-redux/OTP-RR Main UI Translate-URL: https://hosted.weblate.org/projects/otp-react-redux/otp-rr-main-ui/ --- i18n/nb_NO.yml | 1 - i18n/ru.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/i18n/nb_NO.yml b/i18n/nb_NO.yml index f65100277..a3c25a12f 100644 --- a/i18n/nb_NO.yml +++ b/i18n/nb_NO.yml @@ -104,7 +104,6 @@ components: requestNewCode: Forespør ny kode sendVerificationText: Send bekreftelsestekst verificationCode: Bekreftelseskode - verified: Bekreftet verify: Bekreft Place: deleteThisPlace: Slett dette stedet diff --git a/i18n/ru.yml b/i18n/ru.yml index 09ee5e6f6..9e8f20b2f 100644 --- a/i18n/ru.yml +++ b/i18n/ru.yml @@ -402,7 +402,6 @@ components: verificationInstructions: "Откройте приложение для обмена SMS на телефоне и найдите текстовое сообщение с кодом подтверждения. Затем введите код ниже (срок действия кода: 10 минут).\n" - verified: Подтверждено verify: Подтвердить Place: deleteThisPlace: Удалить это место From fd6dafb08eba446dfb7a41a11ab385fae2221001 Mon Sep 17 00:00:00 2001 From: amy-corson-ibigroup <115499534+amy-corson-ibigroup@users.noreply.github.com> Date: Mon, 25 Nov 2024 13:54:40 -0600 Subject: [PATCH 08/16] Only call stopTimes if we don't already have the data --- lib/actions/apiV2.js | 7 +++++++ lib/components/viewers/stop-schedule-viewer.tsx | 8 ++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/actions/apiV2.js b/lib/actions/apiV2.js index e7deb84e3..626243897 100644 --- a/lib/actions/apiV2.js +++ b/lib/actions/apiV2.js @@ -505,6 +505,13 @@ export const fetchNearby = (position, radius, currentServiceWeek) => { export const findStopTimesForStop = (params) => function (dispatch, getState) { + // If the stop is already in the store, don't fetch it again, unless we are forcing a refetch + if ( + !params.forceFetch && + getState().otp.transitIndex.stops[params.stopId] + ) { + return + } dispatch(fetchingStopTimesForStop(params)) const { date, stopId } = params const timeZone = getState().otp.config.homeTimezone diff --git a/lib/components/viewers/stop-schedule-viewer.tsx b/lib/components/viewers/stop-schedule-viewer.tsx index 51f85c967..8b62234c8 100644 --- a/lib/components/viewers/stop-schedule-viewer.tsx +++ b/lib/components/viewers/stop-schedule-viewer.tsx @@ -33,7 +33,11 @@ import TimezoneWarning from './timezone-warning' interface Props { calendarMax: string calendarMin: string - findStopTimesForStop: (arg: { date: string; stopId: string }) => void + findStopTimesForStop: (arg: { + date: string + forceFetch?: boolean + stopId: string + }) => void hideBackButton?: boolean homeTimezone: string intl: IntlShape @@ -137,7 +141,7 @@ class StopScheduleViewer extends Component { _findStopTimesForDate = (date: string) => { const { findStopTimesForStop, stopId } = this.props if (stopId) { - findStopTimesForStop({ date, stopId }) + findStopTimesForStop({ date, forceFetch: true, stopId }) } } From 20047af21b3835b311c83123222f0104821e4195 Mon Sep 17 00:00:00 2001 From: amy-corson-ibigroup <115499534+amy-corson-ibigroup@users.noreply.github.com> Date: Tue, 26 Nov 2024 18:06:31 -0600 Subject: [PATCH 09/16] feat: add network connection status to ui and redux --- i18n/en-US.yml | 2 + lib/actions/ui.js | 3 + lib/components/app/desktop-nav.tsx | 8 ++ .../app/network-connection-banner.tsx | 78 +++++++++++++++++++ lib/components/app/responsive-webapp.js | 6 +- lib/components/mobile/navigation-bar.js | 9 ++- lib/reducers/create-otp-reducer.js | 12 +++ 7 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 lib/components/app/network-connection-banner.tsx diff --git a/i18n/en-US.yml b/i18n/en-US.yml index e3f9c8025..9bb360c76 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -183,6 +183,8 @@ components: closeMenu: Close Menu fieldTrip: Field Trip mailables: Mailables + networkConnectionLost: Network connection lost + networkConnectionRestored: Network connection restored openMenu: Open Menu skipNavigation: Skip navigation BackToTripPlanner: diff --git a/lib/actions/ui.js b/lib/actions/ui.js index cdd0691da..a548a43bc 100644 --- a/lib/actions/ui.js +++ b/lib/actions/ui.js @@ -47,6 +47,9 @@ const viewRoute = createAction('SET_VIEWED_ROUTE') export const toggleAutoRefresh = createAction('TOGGLE_AUTO_REFRESH') const settingItineraryView = createAction('SET_ITINERARY_VIEW') export const setPopupContent = createAction('SET_POPUP_CONTENT') +export const setNetworkConnectionLost = createAction( + 'SET_NETWORK_CONNECTION_LOST' +) // This code-less action calls the reducer code // and thus resets the session timeout. diff --git a/lib/components/app/desktop-nav.tsx b/lib/components/app/desktop-nav.tsx index f9a265b86..ef692d88c 100644 --- a/lib/components/app/desktop-nav.tsx +++ b/lib/components/app/desktop-nav.tsx @@ -13,6 +13,7 @@ import { DEFAULT_APP_TITLE } from '../../util/constants' import InvisibleA11yLabel from '../util/invisible-a11y-label' import NavLoginButtonAuth0 from '../user/nav-login-button-auth0' +import { NetworkConnectionBanner } from './network-connection-banner' import AppMenu, { Icon } from './app-menu' import LocaleSelector from './locale-selector' import NavbarItem from './nav-item' @@ -63,6 +64,7 @@ const NavItemOnLargeScreens = styled(NavbarItem)` // Typscript TODO: otpConfig type export type Props = { locale: string + networkConnectionLost: boolean otpConfig: AppConfig popupTarget?: string setPopupContent: (url: string) => void @@ -83,6 +85,7 @@ export type Props = { */ const DesktopNav = ({ locale, + networkConnectionLost, otpConfig, popupTarget, setPopupContent @@ -117,6 +120,8 @@ const DesktopNav = ({ id: `config.popups.${popupTarget}` }) + console.log(networkConnectionLost) + return (
@@ -166,6 +171,7 @@ const DesktopNav = ({ +
) } @@ -173,8 +179,10 @@ const DesktopNav = ({ // connect to the redux store const mapStateToProps = (state: AppReduxState) => { const { config: otpConfig } = state.otp + const { networkConnectionLost } = state.otp.ui.errors return { locale: state.otp.ui.locale, + networkConnectionLost, otpConfig, popupTarget: otpConfig.popups?.launchers?.toolbar } diff --git a/lib/components/app/network-connection-banner.tsx b/lib/components/app/network-connection-banner.tsx new file mode 100644 index 000000000..9ea7de51b --- /dev/null +++ b/lib/components/app/network-connection-banner.tsx @@ -0,0 +1,78 @@ +import { CSSTransition, TransitionGroup } from 'react-transition-group' +import { FormattedMessage } from 'react-intl' +import React, { useRef } from 'react' +import styled from 'styled-components' + +import { RED_ON_WHITE } from '../util/colors' + +const containerClassname = 'network-connection-banner' +const timeout = 200 + +const TransitionStyles = styled.div` + .${containerClassname} { + background: ${RED_ON_WHITE}; + border-left: 1px solid #e7e7e7; + border-right: 1px solid #e7e7e7; + color: #fff; + font-weight: 600; + padding: 5px; + position: absolute; + text-align: center; + top: 50px; + width: 100%; + z-index: 1; + } + .${containerClassname}-enter { + opacity: 0; + transform: translateY(-100%); + } + .${containerClassname}-enter-active { + opacity: 1; + transform: translateY(0); + transition: opacity ${timeout}ms ease-in; + } + .${containerClassname}-exit { + opacity: 1; + transform: translateY(0); + } + .${containerClassname}-exit-active { + opacity: 0; + transform: translateY(-100%); + transition: opacity ${timeout}ms ease-in, transform ${timeout}ms ease-in; + } +` +export const NetworkConnectionLostBanner = styled.div`` + +export const NetworkConnectionBanner = ({ + networkConnectionLost +}: { + networkConnectionLost: boolean +}): JSX.Element => { + const connectionLostBannerRef = useRef(null) + return ( + + + {networkConnectionLost && ( + + + {networkConnectionLost ? ( + + ) : ( + + )} + + + )} + + + ) +} diff --git a/lib/components/app/responsive-webapp.js b/lib/components/app/responsive-webapp.js index 2b2a44dfc..15e5d4a22 100644 --- a/lib/components/app/responsive-webapp.js +++ b/lib/components/app/responsive-webapp.js @@ -154,10 +154,13 @@ class ResponsiveWebapp extends Component { map, matchContentToUrl, parseUrlQueryString, - receivedPositionResponse + receivedPositionResponse, + setNetworkConnectionLost } = this.props // Add on back button press behavior. window.addEventListener('popstate', handleBackButtonPress) + window.addEventListener('online', () => setNetworkConnectionLost(false)) + window.addEventListener('offline', () => setNetworkConnectionLost(true)) // If a URL is detected without hash routing (e.g., http://localhost:9966?sessionId=test), // window.location.search will have a value. In this case, we need to redirect to the URL root with the @@ -441,6 +444,7 @@ const mapStateToWrapperProps = (state) => { const mapWrapperDispatchToProps = { processSignIn: authActions.processSignIn, setLocale: uiActions.setLocale, + setNetworkConnectionLost: uiActions.setNetworkConnectionLost, showAccessTokenError: authActions.showAccessTokenError, showLoginError: authActions.showLoginError } diff --git a/lib/components/mobile/navigation-bar.js b/lib/components/mobile/navigation-bar.js index 4426a244c..eaa071f3d 100644 --- a/lib/components/mobile/navigation-bar.js +++ b/lib/components/mobile/navigation-bar.js @@ -9,6 +9,7 @@ import * as uiActions from '../../actions/ui' import { accountLinks, getAuth0Config } from '../../util/auth' import { ComponentContext } from '../../util/contexts' import { injectIntl } from 'react-intl' +import { NetworkConnectionBanner } from '../app/network-connection-banner' import { StyledIconWrapper } from '../util/styledIcon' import AppMenu from '../app/app-menu' import LocaleSelector from '../app/locale-selector' @@ -32,6 +33,7 @@ class MobileNavigationBar extends Component { headerText: PropTypes.string, intl: PropTypes.object, locale: PropTypes.string, + networkConnectionLost: PropTypes.bool, onBackClicked: PropTypes.func, setMobileScreen: PropTypes.func, showBackButton: PropTypes.bool @@ -55,6 +57,7 @@ class MobileNavigationBar extends Component { headerText, intl, locale, + networkConnectionLost, showBackButton } = this.props @@ -111,6 +114,9 @@ class MobileNavigationBar extends Component { )} + ) } @@ -123,7 +129,8 @@ const mapStateToProps = (state) => { auth0Config: getAuth0Config(state.otp.config.persistence), configLanguages: state.otp.config.language, extraMenuItems: state.otp?.config?.extraMenuItems, - locale: state.otp.ui.locale + locale: state.otp.ui.locale, + networkConnectionLost: state.otp.ui.errors.networkConnectionLost } } diff --git a/lib/reducers/create-otp-reducer.js b/lib/reducers/create-otp-reducer.js index e753c466c..0028f5095 100644 --- a/lib/reducers/create-otp-reducer.js +++ b/lib/reducers/create-otp-reducer.js @@ -225,6 +225,9 @@ export function getInitialState(userDefinedConfig) { }, ui: { diagramLeg: null, + errors: { + networkConnectionLost: !navigator.onLine + }, locale: null, localizedMessages: null, mainPanelContent: null, @@ -1108,6 +1111,15 @@ function createOtpReducer(config) { } } }) + case 'SET_NETWORK_CONNECTION_LOST': + console.log(action.payload) + return update(state, { + ui: { + errors: { + networkConnectionLost: { $set: action.payload } + } + } + }) case 'SERVICE_TIME_RANGE_REQUEST': return update(state, { serviceTimeRange: { $set: { pending: true } } From 7e30272c8f0a0cc575ce089ea7ee1f098bc78d16 Mon Sep 17 00:00:00 2001 From: amy-corson-ibigroup <115499534+amy-corson-ibigroup@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:22:26 -0600 Subject: [PATCH 10/16] remove unnecessary brackets in return --- lib/actions/apiV2.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/actions/apiV2.js b/lib/actions/apiV2.js index 626243897..9438d5e3d 100644 --- a/lib/actions/apiV2.js +++ b/lib/actions/apiV2.js @@ -506,12 +506,9 @@ export const fetchNearby = (position, radius, currentServiceWeek) => { export const findStopTimesForStop = (params) => function (dispatch, getState) { // If the stop is already in the store, don't fetch it again, unless we are forcing a refetch - if ( - !params.forceFetch && - getState().otp.transitIndex.stops[params.stopId] - ) { + if (!params.forceFetch && getState().otp.transitIndex.stops[params.stopId]) return - } + dispatch(fetchingStopTimesForStop(params)) const { date, stopId } = params const timeZone = getState().otp.config.homeTimezone From 3fcf0592f4358959139a0c497707064f3f309c61 Mon Sep 17 00:00:00 2001 From: amy-corson-ibigroup <115499534+amy-corson-ibigroup@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:17:10 -0600 Subject: [PATCH 11/16] tweak styling and create status region --- lib/components/app/app.css | 3 +++ lib/components/app/desktop-nav.tsx | 11 ++++++++--- .../app/network-connection-banner.tsx | 19 +++++++++++-------- lib/components/mobile/batch-search-screen.tsx | 5 +++-- lib/reducers/create-otp-reducer.js | 1 - 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/lib/components/app/app.css b/lib/components/app/app.css index 87fe44222..e5d39188a 100644 --- a/lib/components/app/app.css +++ b/lib/components/app/app.css @@ -108,6 +108,9 @@ height: 100%; width: 100%; } +.otp .navbar { + z-index: 25; +} /** These changes kick in when the map is hidden. These rules ensure that the entire "sidebar" (which at this point fills the entire screen) scrolls as a single unit. diff --git a/lib/components/app/desktop-nav.tsx b/lib/components/app/desktop-nav.tsx index ef692d88c..a92cd9df5 100644 --- a/lib/components/app/desktop-nav.tsx +++ b/lib/components/app/desktop-nav.tsx @@ -1,7 +1,7 @@ import { connect } from 'react-redux' +import { FormattedMessage, useIntl } from 'react-intl' import { isMobile } from '@opentripplanner/core-utils/lib/ui' import { Nav, Navbar } from 'react-bootstrap' -import { useIntl } from 'react-intl' import React from 'react' import styled from 'styled-components' @@ -120,8 +120,6 @@ const DesktopNav = ({ id: `config.popups.${popupTarget}` }) - console.log(networkConnectionLost) - return (
@@ -171,6 +169,13 @@ const DesktopNav = ({ + + {networkConnectionLost ? ( + + ) : ( + + )} +
) diff --git a/lib/components/app/network-connection-banner.tsx b/lib/components/app/network-connection-banner.tsx index 9ea7de51b..50c4924a0 100644 --- a/lib/components/app/network-connection-banner.tsx +++ b/lib/components/app/network-connection-banner.tsx @@ -6,7 +6,7 @@ import styled from 'styled-components' import { RED_ON_WHITE } from '../util/colors' const containerClassname = 'network-connection-banner' -const timeout = 200 +const timeout = 250 const TransitionStyles = styled.div` .${containerClassname} { @@ -20,7 +20,12 @@ const TransitionStyles = styled.div` text-align: center; top: 50px; width: 100%; - z-index: 1; + // When banner is fully loaded, set z-index higher than nav so we're not seeing the nav border. + z-index: 26; + + @media (max-width: 768px) { + border: 0; + } } .${containerClassname}-enter { opacity: 0; @@ -34,11 +39,13 @@ const TransitionStyles = styled.div` .${containerClassname}-exit { opacity: 1; transform: translateY(0); + z-index: 20; } .${containerClassname}-exit-active { opacity: 0; transform: translateY(-100%); transition: opacity ${timeout}ms ease-in, transform ${timeout}ms ease-in; + z-index: 20; } ` export const NetworkConnectionLostBanner = styled.div`` @@ -62,13 +69,9 @@ export const NetworkConnectionBanner = ({ aria-live="assertive" className={containerClassname} ref={connectionLostBannerRef} - role="status" + role="alert" > - {networkConnectionLost ? ( - - ) : ( - - )} + )} diff --git a/lib/components/mobile/batch-search-screen.tsx b/lib/components/mobile/batch-search-screen.tsx index 5be2cc8c7..04e2a850c 100644 --- a/lib/components/mobile/batch-search-screen.tsx +++ b/lib/components/mobile/batch-search-screen.tsx @@ -40,8 +40,9 @@ const MobileSearchSettings = styled.div<{ top: 50px; transition: ${(props) => `all ${props.transitionDuration}ms ease`}; transition-delay: ${(props) => props.transitionDelay}ms; - /* Must appear under the 'hamburger' dropdown which has z-index of 1000. */ - z-index: 999; + /* Must appear under the 'hamburger' dropdown which has z-index of 1000, and the "network lost" + banner which has a z-index of 10 */ + z-index: 9; ` interface Props { diff --git a/lib/reducers/create-otp-reducer.js b/lib/reducers/create-otp-reducer.js index 0028f5095..9d66ab43b 100644 --- a/lib/reducers/create-otp-reducer.js +++ b/lib/reducers/create-otp-reducer.js @@ -1112,7 +1112,6 @@ function createOtpReducer(config) { } }) case 'SET_NETWORK_CONNECTION_LOST': - console.log(action.payload) return update(state, { ui: { errors: { From f8141fd46567593e7a9848524a67584ae00e03ac Mon Sep 17 00:00:00 2001 From: amy-corson-ibigroup <115499534+amy-corson-ibigroup@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:23:40 -0600 Subject: [PATCH 12/16] Add status region to mobile --- lib/components/mobile/navigation-bar.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/components/mobile/navigation-bar.js b/lib/components/mobile/navigation-bar.js index eaa071f3d..555690226 100644 --- a/lib/components/mobile/navigation-bar.js +++ b/lib/components/mobile/navigation-bar.js @@ -1,5 +1,6 @@ import { ArrowLeft } from '@styled-icons/fa-solid/ArrowLeft' import { connect } from 'react-redux' +import { FormattedMessage, injectIntl } from 'react-intl' import { Navbar } from 'react-bootstrap' import PropTypes from 'prop-types' import React, { Component } from 'react' @@ -8,10 +9,10 @@ import styled from 'styled-components' import * as uiActions from '../../actions/ui' import { accountLinks, getAuth0Config } from '../../util/auth' import { ComponentContext } from '../../util/contexts' -import { injectIntl } from 'react-intl' import { NetworkConnectionBanner } from '../app/network-connection-banner' import { StyledIconWrapper } from '../util/styledIcon' import AppMenu from '../app/app-menu' +import InvisibleA11yLabel from '../util/invisible-a11y-label' import LocaleSelector from '../app/locale-selector' import NavLoginButtonAuth0 from '../../components/user/nav-login-button-auth0' import PageTitle from '../util/page-title' @@ -114,6 +115,13 @@ class MobileNavigationBar extends Component { )} + + {networkConnectionLost ? ( + + ) : ( + + )} + From 27bd54808ed4c227f05889329017eaff7d24fa39 Mon Sep 17 00:00:00 2001 From: amy-corson-ibigroup <115499534+amy-corson-ibigroup@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:35:53 -0600 Subject: [PATCH 13/16] consolidate network connection status regions into one --- lib/components/app/desktop-nav.tsx | 9 +-------- .../app/network-connection-banner.tsx | 18 ++++++++++-------- lib/components/mobile/navigation-bar.js | 10 +--------- 3 files changed, 12 insertions(+), 25 deletions(-) diff --git a/lib/components/app/desktop-nav.tsx b/lib/components/app/desktop-nav.tsx index a92cd9df5..43b4ca919 100644 --- a/lib/components/app/desktop-nav.tsx +++ b/lib/components/app/desktop-nav.tsx @@ -1,7 +1,7 @@ import { connect } from 'react-redux' -import { FormattedMessage, useIntl } from 'react-intl' import { isMobile } from '@opentripplanner/core-utils/lib/ui' import { Nav, Navbar } from 'react-bootstrap' +import { useIntl } from 'react-intl' import React from 'react' import styled from 'styled-components' @@ -169,13 +169,6 @@ const DesktopNav = ({ - - {networkConnectionLost ? ( - - ) : ( - - )} - ) diff --git a/lib/components/app/network-connection-banner.tsx b/lib/components/app/network-connection-banner.tsx index 50c4924a0..a323520ac 100644 --- a/lib/components/app/network-connection-banner.tsx +++ b/lib/components/app/network-connection-banner.tsx @@ -4,6 +4,7 @@ import React, { useRef } from 'react' import styled from 'styled-components' import { RED_ON_WHITE } from '../util/colors' +import InvisibleA11yLabel from '../util/invisible-a11y-label' const containerClassname = 'network-connection-banner' const timeout = 250 @@ -48,7 +49,6 @@ const TransitionStyles = styled.div` z-index: 20; } ` -export const NetworkConnectionLostBanner = styled.div`` export const NetworkConnectionBanner = ({ networkConnectionLost @@ -58,6 +58,13 @@ export const NetworkConnectionBanner = ({ const connectionLostBannerRef = useRef(null) return ( + + {networkConnectionLost ? ( + + ) : ( + + )} + {networkConnectionLost && ( - +
- +
)}
diff --git a/lib/components/mobile/navigation-bar.js b/lib/components/mobile/navigation-bar.js index 555690226..1e7b0079c 100644 --- a/lib/components/mobile/navigation-bar.js +++ b/lib/components/mobile/navigation-bar.js @@ -1,6 +1,6 @@ import { ArrowLeft } from '@styled-icons/fa-solid/ArrowLeft' import { connect } from 'react-redux' -import { FormattedMessage, injectIntl } from 'react-intl' +import { injectIntl } from 'react-intl' import { Navbar } from 'react-bootstrap' import PropTypes from 'prop-types' import React, { Component } from 'react' @@ -12,7 +12,6 @@ import { ComponentContext } from '../../util/contexts' import { NetworkConnectionBanner } from '../app/network-connection-banner' import { StyledIconWrapper } from '../util/styledIcon' import AppMenu from '../app/app-menu' -import InvisibleA11yLabel from '../util/invisible-a11y-label' import LocaleSelector from '../app/locale-selector' import NavLoginButtonAuth0 from '../../components/user/nav-login-button-auth0' import PageTitle from '../util/page-title' @@ -115,13 +114,6 @@ class MobileNavigationBar extends Component { )} - - {networkConnectionLost ? ( - - ) : ( - - )} - From 9ab8492883568a17ff85a727b3718395daa2d008 Mon Sep 17 00:00:00 2001 From: amy-corson-ibigroup <115499534+amy-corson-ibigroup@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:56:45 -0600 Subject: [PATCH 14/16] French translations for network connection strings --- i18n/fr.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i18n/fr.yml b/i18n/fr.yml index a8283e9f1..b7bddef7a 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -194,6 +194,8 @@ components: closeMenu: Fermer le menu fieldTrip: Groupes scolaires mailables: Prêt-à-poster + networkConnectionLost: Erreur de connexion réseau + networkConnectionRestored: Connexion réseau restaurée openMenu: Ouvrir le menu skipNavigation: Sauter la navigation BackToTripPlanner: From b276b6ba761d5ef449abb064ed39626a609bd953 Mon Sep 17 00:00:00 2001 From: josh-willis-arcadis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:38:19 -0600 Subject: [PATCH 15/16] fix(trip-basics-pane): remove ability to select days that the trip isn't available --- lib/components/user/monitored-trip/trip-basics-pane.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/components/user/monitored-trip/trip-basics-pane.tsx b/lib/components/user/monitored-trip/trip-basics-pane.tsx index dafafcd00..e3685dcec 100644 --- a/lib/components/user/monitored-trip/trip-basics-pane.tsx +++ b/lib/components/user/monitored-trip/trip-basics-pane.tsx @@ -180,9 +180,8 @@ const RenderAvailableDays = ({ title={notAvailableText} > Date: Wed, 4 Dec 2024 13:15:24 -0600 Subject: [PATCH 16/16] Update snapshots --- .../viewers/__snapshots__/nearby-view.js.snap | 496 +++++++++--------- .../__snapshots__/create-otp-reducer.js.snap | 3 + 2 files changed, 251 insertions(+), 248 deletions(-) diff --git a/__tests__/components/viewers/__snapshots__/nearby-view.js.snap b/__tests__/components/viewers/__snapshots__/nearby-view.js.snap index a3a1b7bc5..65c9368a3 100644 --- a/__tests__/components/viewers/__snapshots__/nearby-view.js.snap +++ b/__tests__/components/viewers/__snapshots__/nearby-view.js.snap @@ -46,7 +46,7 @@ exports[`components > viewers > nearby view renders nothing on a blank page 1`] className="nearby-view base-color-bg" >
viewers > nearby view renders nothing on a blank page 1`] } >
    viewers > nearby view renders proper scooter dates 1`] = ` className="nearby-view base-color-bg" >
    viewers > nearby view renders proper scooter dates 1`] = ` } >
      viewers > nearby view renders proper scooter dates 1`] = ` >

      viewers > nearby view renders proper scooter dates 1`] = ` >

      viewers > nearby view renders proper scooter dates 1`] = `

      viewers > nearby view renders proper scooter dates 1`] = ` >

      viewers > nearby view renders proper scooter dates 1`] = ` >

      viewers > nearby view renders proper scooter dates 1`] = `

      viewers > nearby view renders proper scooter dates 1`] = ` >

      viewers > nearby view renders proper scooter dates 1`] = ` >

      viewers > nearby view renders proper scooter dates 1`] = `

      viewers > nearby view renders proper scooter dates 1`] = ` >
      viewers > nearby view renders proper scooter dates 1`] = ` >

      viewers > nearby view renders proper scooter dates 1`] = ` >

      viewers > nearby view renders proper scooter dates 1`] = `

      viewers > nearby view renders proper scooter dates 1`] = `
        viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >
      • viewers > nearby view renders proper scooter dates 1`] = ` title="45" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

          viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

        1. viewers > nearby view renders proper scooter dates 1`] = ` title="62" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

            viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

          1. viewers > nearby view renders proper scooter dates 1`] = ` title="79" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

              viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

              viewers > nearby view renders proper scooter dates 1`] = ` >

              viewers > nearby view renders proper scooter dates 1`] = ` >

              viewers > nearby view renders proper scooter dates 1`] = `

              viewers > nearby view renders proper scooter dates 1`] = `
                viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >
              • viewers > nearby view renders proper scooter dates 1`] = ` title="1 Line" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                  viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                1. viewers > nearby view renders proper scooter dates 1`] = ` title="1 Line" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                    viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                  1. viewers > nearby view renders proper scooter dates 1`] = ` title="1 Line" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                      viewers > nearby view renders proper scooter dates 1`] = ` >

                      viewers > nearby view renders proper scooter dates 1`] = ` >

                      viewers > nearby view renders proper scooter dates 1`] = `

                      viewers > nearby view renders proper scooter dates 1`] = ` >

                      viewers > nearby view renders proper scooter dates 1`] = ` >

                      viewers > nearby view renders proper scooter dates 1`] = `

                      viewers > nearby view renders proper scooter dates 1`] = ` >

                      viewers > nearby view renders proper scooter dates 1`] = ` >

                      viewers > nearby view renders proper scooter dates 1`] = `

                      viewers > nearby view renders proper scooter dates 1`] = ` >
                      viewers > nearby view renders proper scooter dates 1`] = ` >

                      viewers > nearby view renders proper scooter dates 1`] = ` >

                      viewers > nearby view renders proper scooter dates 1`] = `

                      viewers > nearby view renders proper scooter dates 1`] = `
                        viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >
                      • viewers > nearby view renders proper scooter dates 1`] = ` title="45" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                          viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                        1. viewers > nearby view renders proper scooter dates 1`] = ` title="62" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                            viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                          1. viewers > nearby view renders proper scooter dates 1`] = ` title="79" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                              viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                            1. viewers > nearby view renders proper scooter dates 1`] = ` title="988" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = `

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = `

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = `

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = `

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = `

                                viewers > nearby view renders proper scooter dates 1`] = ` >
                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = ` >

                                viewers > nearby view renders proper scooter dates 1`] = `

                                viewers > nearby view renders proper scooter dates 1`] = `
                                  viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >
                                • viewers > nearby view renders proper scooter dates 1`] = ` title="67" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                    viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                                  1. viewers > nearby view renders proper scooter dates 1`] = ` title="73" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                      viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                                    1. viewers > nearby view renders proper scooter dates 1`] = ` title="984" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                        viewers > nearby view renders proper scooter dates 1`] = ` >

                                        viewers > nearby view renders proper scooter dates 1`] = ` >

                                        viewers > nearby view renders proper scooter dates 1`] = `

                                        viewers > nearby view renders proper scooter dates 1`] = ` >
                                        viewers > nearby view renders proper scooter dates 1`] = ` >

                                        viewers > nearby view renders proper scooter dates 1`] = ` >

                                        viewers > nearby view renders proper scooter dates 1`] = `

                                        viewers > nearby view renders proper scooter dates 1`] = `
                                          viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >
                                        • viewers > nearby view renders proper scooter dates 1`] = ` title="1 Line" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                            viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                                            viewers > nearby view renders proper scooter dates 1`] = ` >

                                            viewers > nearby view renders proper scooter dates 1`] = ` >

                                            viewers > nearby view renders proper scooter dates 1`] = `

                                            viewers > nearby view renders proper scooter dates 1`] = `
                                              viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >
                                            • viewers > nearby view renders proper scooter dates 1`] = ` title="522" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                                              1. viewers > nearby view renders proper scooter dates 1`] = ` title="67" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                  viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                                                1. viewers > nearby view renders proper scooter dates 1`] = ` title="522" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                    viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                                                  1. viewers > nearby view renders proper scooter dates 1`] = ` title="73" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                      viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                                                    1. viewers > nearby view renders proper scooter dates 1`] = ` title="322" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                        viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                                                      1. viewers > nearby view renders proper scooter dates 1`] = ` title="322" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                          viewers > nearby view renders proper scooter dates 1`] = ` >

                                                          viewers > nearby view renders proper scooter dates 1`] = ` >

                                                          viewers > nearby view renders proper scooter dates 1`] = `

                                                          viewers > nearby view renders proper scooter dates 1`] = ` >
                                                          viewers > nearby view renders proper scooter dates 1`] = ` >

                                                          viewers > nearby view renders proper scooter dates 1`] = ` >

                                                          viewers > nearby view renders proper scooter dates 1`] = `

                                                          viewers > nearby view renders proper scooter dates 1`] = `
                                                            viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >
                                                          • viewers > nearby view renders proper scooter dates 1`] = ` title="45" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                              viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                                                            1. viewers > nearby view renders proper scooter dates 1`] = ` title="62" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                                viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                                                              1. viewers > nearby view renders proper scooter dates 1`] = ` title="79" > viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                                  viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >