From 57bb8b1f04cdb925321dcc6b921b8249264b84fb Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 11 May 2023 16:38:01 -0400
Subject: [PATCH 01/49] refactor(NotificationPrefsPane): Remove redundant
header
---
i18n/en-US.yml | 1 -
i18n/es.yml | 30 +++++++------------
i18n/fr.yml | 3 --
i18n/ko.yml | 1 -
i18n/vi.yml | 3 --
i18n/zh.yml | 1 -
.../user/notification-prefs-pane.tsx | 3 --
7 files changed, 10 insertions(+), 32 deletions(-)
diff --git a/i18n/en-US.yml b/i18n/en-US.yml
index b2e036689..e8b46ea69 100644
--- a/i18n/en-US.yml
+++ b/i18n/en-US.yml
@@ -356,7 +356,6 @@ components:
description: The content you requested is not available.
header: Content not found
NotificationPrefsPane:
- description: You can receive notifications about trips you frequently take.
noneSelect: Don't notify me
notificationChannelPrompt: How would you like to receive notifications?
notificationEmailDetail: "Notification emails will be sent to:"
diff --git a/i18n/es.yml b/i18n/es.yml
index 08c82b945..29a962b6d 100644
--- a/i18n/es.yml
+++ b/i18n/es.yml
@@ -30,8 +30,7 @@ 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:"
@@ -47,11 +46,9 @@ 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.
+ itineraryExistenceCheckFailed: Comprobación de errores para ver si el viaje seleccionado es posible.
preferencesSaved: Sus preferencias se han guardado.
smsInvalidCode: El código introducido no es válido. Por favor, inténtelo de nuevo.
smsResendThrottled: >-
@@ -113,6 +110,7 @@ common:
{co2} de CO₂ en {isMore, select, true {más} other {menos} } que conducir
solo
transfers: "{transfers, plural, =0 {} one {# transferencia} other {# transferencias}}"
+ linkOpensNewWindow: (Abre una nueva ventana)
modes:
bicycle_rent: Compartir bicicleta
bike: Bicicleta
@@ -160,7 +158,6 @@ common:
tripDurationFormat: >-
{hours, plural, =0 {} other {# h }}{minutes} min { seconds, plural, =0 {}
other {# s}}
- linkOpensNewWindow: (Abre una nueva ventana)
components:
A11yPrefs:
accessibilityRoutingByDefault: Prefiera los viajes accesibles por defecto
@@ -237,8 +234,7 @@ components:
origin: origen
planTripTooltip: Planificar viaje
settings: Preferencias de 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: >
@@ -366,11 +362,9 @@ components:
description: El contenido que ha solicitado no está disponible.
header: No se encontró el contenido
NotificationPrefsPane:
- description: Puede recibir notificaciones sobre los viajes que realiza con frecuencia.
noneSelect: No enviar notificaciones
notificationChannelPrompt: ¿Cómo desea recibir las notificaciones?
- notificationEmailDetail: "Los correos electrónicos de notificación se enviarán\
- \ a:"
+ notificationEmailDetail: "Los correos electrónicos de notificación se enviarán a:"
PhoneNumberEditor:
changeNumber: Cambiar número de teléfono
invalidCode: Introduzca 6 dígitos para el código de validación.
@@ -503,8 +497,7 @@ components:
Opciones
y Preferencias del viaje
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:
@@ -566,19 +559,16 @@ 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…
selectAtLeastOneDay: Por favor, seleccione al menos un día para el seguimiento.
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
diff --git a/i18n/fr.yml b/i18n/fr.yml
index 925933b69..29c3ee110 100644
--- a/i18n/fr.yml
+++ b/i18n/fr.yml
@@ -368,9 +368,6 @@ components:
description: Le contenu que vous avez demandé n'est pas disponible.
header: Contenu introuvable
NotificationPrefsPane:
- description: >-
- Vous pouvez recevoir des notifications sur les trajets que vous effectuez
- fréquemment.
noneSelect: Ne pas me notifier
notificationChannelPrompt: Comment voulez-vous recevoir vos notifications ?
notificationEmailDetail: "Les courriers de notification seront envoyés à :"
diff --git a/i18n/ko.yml b/i18n/ko.yml
index a4d9f9afa..605c75f7a 100644
--- a/i18n/ko.yml
+++ b/i18n/ko.yml
@@ -335,7 +335,6 @@ components:
description: 요청한 콘텐츠를 사용할 수 없습니다.
header: 콘텐츠를 찾을 수 없음
NotificationPrefsPane:
- description: 자주 가는 트립에 대한 알림을 받을 수 있습니다.
noneSelect: 알림 거부
notificationChannelPrompt: 알림을 어떻게 받고 싶습니까?
notificationEmailDetail: "알림 이메일이 다음으로 전송됩니다:"
diff --git a/i18n/vi.yml b/i18n/vi.yml
index 854e37905..64f48d2d3 100644
--- a/i18n/vi.yml
+++ b/i18n/vi.yml
@@ -343,9 +343,6 @@ 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:
- description: >-
- Bạn có thể nhận được thông báo về các chuyến đi bạn thường xuyên thực
- hiện.
noneSelect: Đừng thông báo cho tôi
notificationChannelPrompt: Bạn muốn nhận thông báo như thế nào?
notificationEmailDetail: "Email thông báo sẽ được gửi đến:"
diff --git a/i18n/zh.yml b/i18n/zh.yml
index e44e03592..bc32777c4 100644
--- a/i18n/zh.yml
+++ b/i18n/zh.yml
@@ -335,7 +335,6 @@ components:
description: 您要求的内容不存在.
header: 未找到内容
NotificationPrefsPane:
- description: 你可以收到关于你常用行程的通知.
noneSelect: 不要通知我
notificationChannelPrompt: 您希望如何接收通知?
notificationEmailDetail: "通知邮件将被发送至:"
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index 4bee1cca9..ac9ea0ca8 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -53,9 +53,6 @@ const NotificationPrefsPane = ({
return (
-
-
-
From 18aa10220ff8dbbf1a3fa1381f5a39cbcb7e7e7b Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 11 May 2023 16:56:11 -0400
Subject: [PATCH 02/49] refactor(NotificationPrefsPane): Rephrase the
notification selector prompt.
---
i18n/en-US.yml | 2 +-
i18n/es.yml | 2 +-
i18n/fr.yml | 2 +-
i18n/ko.yml | 2 +-
i18n/vi.yml | 2 +-
i18n/zh.yml | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/i18n/en-US.yml b/i18n/en-US.yml
index e8b46ea69..e13f71b32 100644
--- a/i18n/en-US.yml
+++ b/i18n/en-US.yml
@@ -357,7 +357,7 @@ components:
header: Content not found
NotificationPrefsPane:
noneSelect: Don't notify me
- notificationChannelPrompt: How would you like to receive notifications?
+ notificationChannelPrompt: "Receive notifications about your saved trips via:"
notificationEmailDetail: "Notification emails will be sent to:"
PhoneNumberEditor:
changeNumber: Change number
diff --git a/i18n/es.yml b/i18n/es.yml
index 29a962b6d..e6142f4fc 100644
--- a/i18n/es.yml
+++ b/i18n/es.yml
@@ -363,7 +363,7 @@ components:
header: No se encontró el contenido
NotificationPrefsPane:
noneSelect: No enviar notificaciones
- notificationChannelPrompt: ¿Cómo desea recibir las notificaciones?
+ notificationChannelPrompt: "Recibir notificaciones para sus viajes guardados por :"
notificationEmailDetail: "Los correos electrónicos de notificación se enviarán a:"
PhoneNumberEditor:
changeNumber: Cambiar número de teléfono
diff --git a/i18n/fr.yml b/i18n/fr.yml
index 29c3ee110..4133097ed 100644
--- a/i18n/fr.yml
+++ b/i18n/fr.yml
@@ -369,7 +369,7 @@ components:
header: Contenu introuvable
NotificationPrefsPane:
noneSelect: Ne pas me notifier
- notificationChannelPrompt: Comment voulez-vous recevoir vos notifications ?
+ notificationChannelPrompt: "Recevoir des notifications sur vos trajets enregistrés par :"
notificationEmailDetail: "Les courriers de notification seront envoyés à :"
PhoneNumberEditor:
changeNumber: Changer de numéro
diff --git a/i18n/ko.yml b/i18n/ko.yml
index 605c75f7a..71434375c 100644
--- a/i18n/ko.yml
+++ b/i18n/ko.yml
@@ -336,7 +336,7 @@ components:
header: 콘텐츠를 찾을 수 없음
NotificationPrefsPane:
noneSelect: 알림 거부
- notificationChannelPrompt: 알림을 어떻게 받고 싶습니까?
+ notificationChannelPrompt: "저장된 여행의 알림을 받는 방법:"
notificationEmailDetail: "알림 이메일이 다음으로 전송됩니다:"
PhoneNumberEditor:
changeNumber: 번호 변경
diff --git a/i18n/vi.yml b/i18n/vi.yml
index 64f48d2d3..694873eb5 100644
--- a/i18n/vi.yml
+++ b/i18n/vi.yml
@@ -344,7 +344,7 @@ components:
header: Không tìm thấy nội dung
NotificationPrefsPane:
noneSelect: Đừng thông báo cho tôi
- notificationChannelPrompt: Bạn muốn nhận thông báo như thế nào?
+ notificationChannelPrompt: "Nhận thông báo về các chuyến đi đã lưu bằng:"
notificationEmailDetail: "Email thông báo sẽ được gửi đến:"
PhoneNumberEditor:
changeNumber: Thay đổi số điện thoại
diff --git a/i18n/zh.yml b/i18n/zh.yml
index bc32777c4..c83ce0d63 100644
--- a/i18n/zh.yml
+++ b/i18n/zh.yml
@@ -336,7 +336,7 @@ components:
header: 未找到内容
NotificationPrefsPane:
noneSelect: 不要通知我
- notificationChannelPrompt: 您希望如何接收通知?
+ notificationChannelPrompt: "如何接收已保存行程的通知:"
notificationEmailDetail: "通知邮件将被发送至:"
PhoneNumberEditor:
changeNumber: 更改电话号码
From 148190bb733d66597b139701b568b9c3b1531b66 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 11 May 2023 18:18:15 -0400
Subject: [PATCH 03/49] refactor(NotificationPrefsPane): Update layout to use
checkboxes (rough)
---
.../user/notification-prefs-pane.tsx | 99 +++++++++++--------
1 file changed, 60 insertions(+), 39 deletions(-)
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index ac9ea0ca8..38dc4713c 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -29,7 +29,7 @@ interface Props extends FormikProps {
}
}
-const allowedNotificationChannels = ['email', 'sms', 'none']
+const allowedNotificationChannels = ['email', 'sms']
// Styles
// HACK: Preserve container height.
@@ -38,6 +38,22 @@ const Details = styled.div`
margin-bottom: 15px;
`
+const NotificationOption = styled.div`
+ align-items: flex-start;
+ display: flex;
+ gap: 1ch;
+ margin-bottom: 10px;
+
+ label {
+ display: block;
+ font-weight: normal;
+ margin-bottom: 0;
+ }
+ label::first-letter {
+ text-transform: uppercase;
+ }
+`
+
/**
* User notification preferences pane.
*/
@@ -53,44 +69,49 @@ const NotificationPrefsPane = ({
return (
-
-
-
-
-
- {allowedNotificationChannels.map((type) => {
- // TODO: If removing the Save/Cancel buttons on the account screen,
- // persist changes immediately when onChange is triggered.
- const inputId = `notification-channel-${type}`
- const isChecked = notificationChannel === type
- return (
-
- {/* Note: labels are placed after inputs so that the CSS focus selector can be easily applied. */}
-
-
- {type === 'email' ? (
-
- ) : type === 'sms' ? (
-
- ) : (
-
- )}
-
-
- )
- })}
-
-
+
+
+
+
+ {allowedNotificationChannels.map((type) => {
+ // TODO: If removing the Save/Cancel buttons on the account screen,
+ // persist changes immediately when onChange is triggered.
+ const inputId = `notification-channel-${type}`
+ return (
+
+ {' '}
+
+ {type === 'email' ? (
+ <>
+
+
+
+ {email}
+ >
+ ) : (
+ <>
+
+
+
+
+ >
+ )}
+
+
+ )
+ })}
+
{notificationChannel === 'email' && (
From 5d04a3953567421558c8e9d6a52a0c1e20d2f66f Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 12 May 2023 11:00:09 -0400
Subject: [PATCH 04/49] refactor(NotificationPrefsPane): Improve layout for
phone number description
---
i18n/en-US.yml | 1 -
i18n/es.yml | 1 -
i18n/fr.yml | 1 -
i18n/ko.yml | 1 -
i18n/vi.yml | 1 -
i18n/zh.yml | 1 -
.../user/notification-prefs-pane.tsx | 51 +++++---------
lib/components/user/phone-number-editor.tsx | 66 +++++++++----------
8 files changed, 49 insertions(+), 74 deletions(-)
diff --git a/i18n/en-US.yml b/i18n/en-US.yml
index e13f71b32..959eb6980 100644
--- a/i18n/en-US.yml
+++ b/i18n/en-US.yml
@@ -370,7 +370,6 @@ components:
prompt: "Enter your phone number for SMS notifications:"
requestNewCode: Request a new code
sendVerificationText: Send verification text
- smsDetail: "SMS notifications will be sent to:"
verificationCode: "Verification code:"
verificationInstructions: >
Please check the SMS messaging app on your mobile phone for a text message
diff --git a/i18n/es.yml b/i18n/es.yml
index e6142f4fc..9cfc2d409 100644
--- a/i18n/es.yml
+++ b/i18n/es.yml
@@ -378,7 +378,6 @@ components:
texto:
requestNewCode: Solicitar un nuevo código
sendVerificationText: Enviar texto de verificación
- smsDetail: "Las notificaciones por mensaje de texto se enviarán a:"
verificationCode: "Código de verificación:"
verificationInstructions: >
Por favor, compruebe en la aplicación de mensajería de texto de su
diff --git a/i18n/fr.yml b/i18n/fr.yml
index 4133097ed..e3bfde8e1 100644
--- a/i18n/fr.yml
+++ b/i18n/fr.yml
@@ -382,7 +382,6 @@ components:
prompt: "Entrez votre numéro de téléphone pour les SMS de notification :"
requestNewCode: Envoyer un nouveau code
sendVerificationText: Envoyer le SMS de vérification
- smsDetail: "Les SMS de notification seront envoyés au :"
verificationCode: "Code de vérification :"
verificationInstructions: >
Un SMS vous a été envoyé avec un code de vérification. Veuillez taper ce
diff --git a/i18n/ko.yml b/i18n/ko.yml
index 71434375c..627b4a9de 100644
--- a/i18n/ko.yml
+++ b/i18n/ko.yml
@@ -348,7 +348,6 @@ components:
prompt: "SMS 알림 수신을 위한 전화번호를 입력하세요:"
requestNewCode: 새 코드 요청
sendVerificationText: 확인 텍스트 전송
- smsDetail: "SMS 알림이 다음으로 전송됩니다:"
verificationCode: "확인 코드:"
verificationInstructions: |
휴대폰의 SMS 메시지 앱에서 인증 코드를 확인하고 아래에 코드를 입력하세요(코드는 10분 후에 만료됩니다).
diff --git a/i18n/vi.yml b/i18n/vi.yml
index 694873eb5..7b582ca5c 100644
--- a/i18n/vi.yml
+++ b/i18n/vi.yml
@@ -356,7 +356,6 @@ components:
prompt: "Nhập số điện thoại của bạn để nhận thông báo SMS:"
requestNewCode: Yêu cầu một mã mới
sendVerificationText: Gửi văn bản xác minh
- smsDetail: "Thông báo SMS sẽ được gửi đến:"
verificationCode: "Mã xác nhận:"
verificationInstructions: >
Vui lòng kiểm tra ứng dụng nhắn tin SMS trên điện thoại di động của bạn để
diff --git a/i18n/zh.yml b/i18n/zh.yml
index c83ce0d63..59f0f3fec 100644
--- a/i18n/zh.yml
+++ b/i18n/zh.yml
@@ -348,7 +348,6 @@ components:
prompt: "输入你的电话号码以便收到短信通知:"
requestNewCode: 申请一个新的代码
sendVerificationText: 发送验证短信
- smsDetail: "短信通知将被发送到:"
verificationCode: "验证码:"
verificationInstructions: |
请检查您手机上的短信应用查看是否有验证码的短信并输入以下代码 (代码在10分钟后失效).
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index 38dc4713c..d929c512a 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -1,12 +1,9 @@
import { Field, FormikProps } from 'formik'
import { FormattedMessage } from 'react-intl'
-import { FormGroup } from 'react-bootstrap'
import React, { Fragment } from 'react'
import styled from 'styled-components'
-import ButtonGroup from '../util/button-group'
-
-import { FakeLabel, InlineStatic } from './styled'
+import { labelStyle } from './styled'
import { PhoneVerificationSubmitHandler } from './phone-verification-form'
import PhoneNumberEditor, {
PhoneCodeRequestHandler
@@ -32,12 +29,6 @@ interface Props extends FormikProps {
const allowedNotificationChannels = ['email', 'sms']
// Styles
-// HACK: Preserve container height.
-const Details = styled.div`
- min-height: 60px;
- margin-bottom: 15px;
-`
-
const NotificationOption = styled.div`
align-items: flex-start;
display: flex;
@@ -54,6 +45,13 @@ const NotificationOption = styled.div`
}
`
+const NotificationOptions = styled.fieldset`
+ /* Format like labels. */
+ legend {
+ ${labelStyle}
+ }
+`
+
/**
* User notification preferences pane.
*/
@@ -62,14 +60,13 @@ const NotificationPrefsPane = ({
onRequestPhoneVerificationCode,
onSendPhoneVerificationCode,
phoneFormatOptions,
- values: userData // Formik prop
+ values: userData // Formik prop // TODO: remove
}: Props): JSX.Element => {
const { email, isPhoneNumberVerified, phoneNumber } = loggedInUser
- const { notificationChannel } = userData
return (
-
+
@@ -77,9 +74,11 @@ const NotificationPrefsPane = ({
// TODO: If removing the Save/Cancel buttons on the account screen,
// persist changes immediately when onChange is triggered.
const inputId = `notification-channel-${type}`
+ const inputDescriptionId = `${inputId}-description`
return (
- {email}
+
+ {email}
+
>
) : (
<>
@@ -99,6 +100,7 @@ const NotificationPrefsPane = ({
)
})}
-
-
- {notificationChannel === 'email' && (
-
-
-
-
- {email}
-
- )}
- {notificationChannel === 'sms' && (
-
- )}
-
+
)
}
diff --git a/lib/components/user/phone-number-editor.tsx b/lib/components/user/phone-number-editor.tsx
index 7e9113a32..4fef908f4 100644
--- a/lib/components/user/phone-number-editor.tsx
+++ b/lib/components/user/phone-number-editor.tsx
@@ -10,7 +10,7 @@ import { isBlank } from '../../util/ui'
import InvisibleA11yLabel from '../util/invisible-a11y-label'
import SpanWithSpace from '../util/span-with-space'
-import { ControlStrip, FakeLabel, InlineStatic } from './styled'
+import { ControlStrip } from './styled'
import PhoneChangeForm, { PhoneChangeSubmitHandler } from './phone-change-form'
import PhoneVerificationForm, {
PhoneVerificationSubmitHandler
@@ -19,7 +19,7 @@ import PhoneVerificationForm, {
export type PhoneCodeRequestHandler = (phoneNumber: string) => void
const PlainLink = styled(SpanWithSpace)`
- color: inherit;
+ color: #757575;
&:hover {
text-decoration: none;
}
@@ -34,6 +34,7 @@ const blankState = {
}
interface Props {
+ descriptorId: string
initialPhoneNumber?: string
initialPhoneNumberVerified?: boolean
intl: IntlShape
@@ -169,7 +170,7 @@ class PhoneNumberEditor extends Component {
}
render() {
- const { initialPhoneNumber, phoneFormatOptions } = this.props
+ const { descriptorId, initialPhoneNumber, phoneFormatOptions } = this.props
const {
isEditing,
phoneNumberReceived,
@@ -220,9 +221,6 @@ class PhoneNumberEditor extends Component {
return (
<>
-
- {ariaAlertContent}
-
{isEditing ? (
{
/>
) : (
-
-
-
-
-
- {shownPhoneNumber}
-
- {/* Invisible parentheses for no-CSS and screen readers */}
- (
- {isPending ? (
-
-
-
- ) : (
-
-
-
- )}
- )
-
+
+ {shownPhoneNumber}
+
+ {/* Invisible parentheses for no-CSS and screen readers */}
+ (
+ {isPending ? (
+
+
+
+ ) : (
+
+
+
+ )}
+ )
)}
+
+ {ariaAlertContent}
+
{isPending && !isEditing && (
Date: Fri, 12 May 2023 12:00:52 -0400
Subject: [PATCH 05/49] refactor(NotificationPrefsPane): Improve layout.
---
.../user/notification-prefs-pane.tsx | 23 ++++++++++++-------
lib/components/user/phone-number-editor.tsx | 10 +++-----
2 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index d929c512a..0e72a4db5 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -32,9 +32,14 @@ const allowedNotificationChannels = ['email', 'sms']
const NotificationOption = styled.div`
align-items: flex-start;
display: flex;
- gap: 1ch;
margin-bottom: 10px;
+ /* Use bootstrap's spacing between checkbox and label */
+ & > span:first-child {
+ flex-shrink: 0;
+ width: 20px;
+ }
+
label {
display: block;
font-weight: normal;
@@ -77,13 +82,15 @@ const NotificationPrefsPane = ({
const inputDescriptionId = `${inputId}-description`
return (
- {' '}
+
+
+
{type === 'email' ? (
<>
diff --git a/lib/components/user/phone-number-editor.tsx b/lib/components/user/phone-number-editor.tsx
index 4fef908f4..62f9c33e4 100644
--- a/lib/components/user/phone-number-editor.tsx
+++ b/lib/components/user/phone-number-editor.tsx
@@ -8,7 +8,6 @@ import styled from 'styled-components'
import { getAriaPhoneNumber } from '../../util/a11y'
import { isBlank } from '../../util/ui'
import InvisibleA11yLabel from '../util/invisible-a11y-label'
-import SpanWithSpace from '../util/span-with-space'
import { ControlStrip } from './styled'
import PhoneChangeForm, { PhoneChangeSubmitHandler } from './phone-change-form'
@@ -18,7 +17,7 @@ import PhoneVerificationForm, {
export type PhoneCodeRequestHandler = (phoneNumber: string) => void
-const PlainLink = styled(SpanWithSpace)`
+const PlainLink = styled.a`
color: #757575;
&:hover {
text-decoration: none;
@@ -232,15 +231,12 @@ class PhoneNumberEditor extends Component {
) : (
+ {/* Use an anchor so that the aria-label applies and phone actions can be performed,
+ if necessary. Styling will make the text appear plain (mostly). */}
{shownPhoneNumber}
From 08fee5bcf3db667ffe92626df52f1f4f090b3791 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 12 May 2023 12:33:14 -0400
Subject: [PATCH 06/49] refactor: Refactor fieldset and color styles.
---
.../user/monitored-trip/trip-basics-pane.tsx | 9 ++------
.../trip-notifications-pane.tsx | 15 +++----------
.../user/notification-prefs-pane.tsx | 22 ++++++++-----------
lib/components/user/phone-number-editor.tsx | 3 ++-
lib/components/user/styled.ts | 15 ++++++-------
lib/components/util/button-group.tsx | 11 ++--------
6 files changed, 25 insertions(+), 50 deletions(-)
diff --git a/lib/components/user/monitored-trip/trip-basics-pane.tsx b/lib/components/user/monitored-trip/trip-basics-pane.tsx
index 3ab97bf9e..b2aa897cc 100644
--- a/lib/components/user/monitored-trip/trip-basics-pane.tsx
+++ b/lib/components/user/monitored-trip/trip-basics-pane.tsx
@@ -18,9 +18,9 @@ import styled from 'styled-components'
import type { IntlShape, WrappedComponentProps } from 'react-intl'
import * as userActions from '../../../actions/user'
+import { FieldSet } from '../styled'
import { getErrorStates } from '../../../util/ui'
import { getFormattedDayOfWeekPlural } from '../../../util/monitored-trip'
-import { labelStyle } from '../styled'
import FormattedDayOfWeek from '../../util/formatted-day-of-week'
import FormattedDayOfWeekCompact from '../../util/formatted-day-of-week-compact'
import FormattedValidationError from '../../util/formatted-validation-error'
@@ -65,12 +65,7 @@ const ALL_DAYS = [
] as const
// Styles.
-const AvailableDays = styled.fieldset`
- /* Format like labels. */
- legend {
- ${labelStyle}
- }
-
+const AvailableDays = styled(FieldSet)`
& > span {
border: 1px solid #ccc;
border-left: none;
diff --git a/lib/components/user/monitored-trip/trip-notifications-pane.tsx b/lib/components/user/monitored-trip/trip-notifications-pane.tsx
index a6702f08a..1428b8c22 100644
--- a/lib/components/user/monitored-trip/trip-notifications-pane.tsx
+++ b/lib/components/user/monitored-trip/trip-notifications-pane.tsx
@@ -5,6 +5,7 @@ import { FormattedMessage, IntlShape, useIntl } from 'react-intl'
import React, { Component, ComponentType, FormEvent, ReactNode } from 'react'
import styled from 'styled-components'
+import { FieldSet } from '../styled'
import { IconWithText } from '../../util/styledIcon'
// Element styles
@@ -36,16 +37,6 @@ const Summary = styled.summary`
margin-bottom: 5px;
`
-const NotificationSettings = styled.fieldset`
- /* Format like labels. */
- legend {
- border: none;
- font-size: inherit;
- font-weight: 700;
- margin-bottom: 5px;
- }
-`
-
/**
* A label followed by a dropdown control.
*/
@@ -214,7 +205,7 @@ class TripNotificationsPane extends Component {
)
} else {
notificationSettingsContent = (
-
+
{
-
+
)
}
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index 0e72a4db5..5d95db2d2 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -3,7 +3,9 @@ import { FormattedMessage } from 'react-intl'
import React, { Fragment } from 'react'
import styled from 'styled-components'
-import { labelStyle } from './styled'
+import { GRAY_ON_WHITE } from '../util/colors'
+
+import { FieldSet } from './styled'
import { PhoneVerificationSubmitHandler } from './phone-verification-form'
import PhoneNumberEditor, {
PhoneCodeRequestHandler
@@ -34,7 +36,7 @@ const NotificationOption = styled.div`
display: flex;
margin-bottom: 10px;
- /* Use bootstrap's spacing between checkbox and label */
+ /* Match bootstrap's spacing between checkbox and label */
& > span:first-child {
flex-shrink: 0;
width: 20px;
@@ -48,12 +50,8 @@ const NotificationOption = styled.div`
label::first-letter {
text-transform: uppercase;
}
-`
-
-const NotificationOptions = styled.fieldset`
- /* Format
like labels. */
- legend {
- ${labelStyle}
+ label + span {
+ color: ${GRAY_ON_WHITE};
}
`
@@ -71,7 +69,7 @@ const NotificationPrefsPane = ({
return (
-
+
@@ -97,9 +95,7 @@ const NotificationPrefsPane = ({
-
- {email}
-
+ {email}
>
) : (
<>
@@ -120,7 +116,7 @@ const NotificationPrefsPane = ({
)
})}
-
+
)
}
diff --git a/lib/components/user/phone-number-editor.tsx b/lib/components/user/phone-number-editor.tsx
index 62f9c33e4..b53d142de 100644
--- a/lib/components/user/phone-number-editor.tsx
+++ b/lib/components/user/phone-number-editor.tsx
@@ -6,6 +6,7 @@ import React, { Component, createRef, Fragment } from 'react'
import styled from 'styled-components'
import { getAriaPhoneNumber } from '../../util/a11y'
+import { GRAY_ON_WHITE } from '../util/colors'
import { isBlank } from '../../util/ui'
import InvisibleA11yLabel from '../util/invisible-a11y-label'
@@ -18,7 +19,7 @@ import PhoneVerificationForm, {
export type PhoneCodeRequestHandler = (phoneNumber: string) => void
const PlainLink = styled.a`
- color: #757575;
+ color: ${GRAY_ON_WHITE};
&:hover {
text-decoration: none;
}
diff --git a/lib/components/user/styled.ts b/lib/components/user/styled.ts
index 092dfdbd8..ae2c07e0d 100644
--- a/lib/components/user/styled.ts
+++ b/lib/components/user/styled.ts
@@ -77,7 +77,7 @@ export const TripPanelFooter = styled(Panel.Footer)`
`
/** Formats non- elements like s. */
-export const labelStyle = css`
+const labelStyle = css`
border: none;
cursor: default;
font-size: inherit;
@@ -85,9 +85,12 @@ export const labelStyle = css`
margin-bottom: 5px;
`
-export const FakeLabel = styled.span`
- display: block;
- ${labelStyle}
+/** Fieldset with a legend that looks like labels. */
+export const FieldSet = styled.fieldset`
+ /* Format like labels. */
+ legend {
+ ${labelStyle}
+ }
`
/** A container with spacing between controls. */
@@ -103,7 +106,3 @@ export const phoneFieldStyle = css`
vertical-align: middle;
width: 14em;
`
-
-export const InlineStatic = styled.span`
- ${phoneFieldStyle}
-`
diff --git a/lib/components/util/button-group.tsx b/lib/components/util/button-group.tsx
index b4a22e214..882c61bbc 100644
--- a/lib/components/util/button-group.tsx
+++ b/lib/components/util/button-group.tsx
@@ -1,17 +1,10 @@
import styled from 'styled-components'
-import { labelStyle } from '../user/styled'
+import { FieldSet } from '../user/styled'
-const ButtonGroup = styled.fieldset.attrs({
+const ButtonGroup = styled(FieldSet).attrs({
className: 'btn-group'
})`
- display: block;
-
- /* Format like labels. */
- legend {
- ${labelStyle}
- }
-
label::first-letter {
text-transform: uppercase;
}
From cd7ca93a54a5c4f7e55209ce40e901b566a00335 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 12 May 2023 15:24:36 -0400
Subject: [PATCH 07/49] refactor(NotificationPrefsPane): Improve layout
---
.../user/notification-prefs-pane.tsx | 111 +++++++++---------
1 file changed, 53 insertions(+), 58 deletions(-)
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index 5d95db2d2..2a034c3bd 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -12,15 +12,13 @@ import PhoneNumberEditor, {
} from './phone-number-editor'
interface Fields {
+ email: string
+ isPhoneNumberVerified?: boolean
notificationChannel: string
+ phoneNumber?: string
}
interface Props extends FormikProps {
- loggedInUser: {
- email: string
- isPhoneNumberVerified?: boolean
- phoneNumber?: string
- }
onRequestPhoneVerificationCode: PhoneCodeRequestHandler
onSendPhoneVerificationCode: PhoneVerificationSubmitHandler
phoneFormatOptions: {
@@ -59,65 +57,62 @@ const NotificationOption = styled.div`
* User notification preferences pane.
*/
const NotificationPrefsPane = ({
- loggedInUser,
onRequestPhoneVerificationCode,
onSendPhoneVerificationCode,
phoneFormatOptions,
- values: userData // Formik prop // TODO: remove
+ values: userData // Formik prop
}: Props): JSX.Element => {
- const { email, isPhoneNumberVerified, phoneNumber } = loggedInUser
+ const { email, isPhoneNumberVerified, phoneNumber } = userData
return (
-
-
-
-
-
- {allowedNotificationChannels.map((type) => {
- // TODO: If removing the Save/Cancel buttons on the account screen,
- // persist changes immediately when onChange is triggered.
- const inputId = `notification-channel-${type}`
- const inputDescriptionId = `${inputId}-description`
- return (
-
-
-
-
-
- {type === 'email' ? (
- <>
-
-
-
- {email}
- >
- ) : (
- <>
-
-
-
-
- >
- )}
-
-
- )
- })}
-
-
+
+
+
+
+ {allowedNotificationChannels.map((type) => {
+ // TODO: If removing the Save/Cancel buttons on the account screen,
+ // persist changes immediately when onChange is triggered.
+ const inputId = `notification-channel-${type}`
+ const inputDescriptionId = `${inputId}-description`
+ return (
+
+
+
+
+
+ {type === 'email' ? (
+ <>
+
+
+
+ {email}
+ >
+ ) : (
+ <>
+
+
+
+
+ >
+ )}
+
+
+ )
+ })}
+
)
}
From e5bd1f6236e055bff456291007686d36baaba2d2 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 12 May 2023 15:39:32 -0400
Subject: [PATCH 08/49] feat(UserAccountScreen): Support saving multiple
notification channels.
---
lib/components/user/user-account-screen.js | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/lib/components/user/user-account-screen.js b/lib/components/user/user-account-screen.js
index 83eefd4b9..b153f5667 100644
--- a/lib/components/user/user-account-screen.js
+++ b/lib/components/user/user-account-screen.js
@@ -5,6 +5,7 @@ import { connect } from 'react-redux'
import { Form, Formik } from 'formik'
import { injectIntl } from 'react-intl'
import { withAuthenticationRequired } from '@auth0/auth0-react'
+import clone from 'clone'
import React, { Component } from 'react'
import * as uiActions from '../../actions/ui'
@@ -26,7 +27,6 @@ const validationSchema = yup.object({
hasConsentedToTerms: yup
.boolean()
.oneOf([true], 'You must agree to the terms to continue.'),
- notificationChannel: yup.string().oneOf(['email', 'sms', 'none']),
savedLocations: yup.array().of(
yup.object({
address: yup.string(),
@@ -43,9 +43,14 @@ const validationSchema = yup.object({
class UserAccountScreen extends Component {
_updateUserPrefs = async (userData, silentOnSucceed = false) => {
const { createOrUpdateUser, intl } = this.props
- // TODO: Change state of Save button while the update action takes place.
- await createOrUpdateUser(userData, silentOnSucceed, intl)
+ // Convert the notification attributes from array to comma-separated string.
+ const passedUserData = clone(userData)
+ const { notificationChannel } = passedUserData
+ if (typeof notificationChannel === 'object' && notificationChannel.length) {
+ passedUserData.notificationChannel = notificationChannel.join(',')
+ }
+ await createOrUpdateUser(passedUserData, silentOnSucceed, intl)
// TODO: Handle UI feedback (currently an alert() dialog inside createOrUpdateUser).
}
@@ -101,20 +106,22 @@ class UserAccountScreen extends Component {
await verifyPhoneNumber(code, intl)
}
- // TODO: Update title bar during componentDidMount.
-
render() {
const { auth0, isCreating, itemId, loggedInUser, phoneFormatOptions } =
this.props
const DisplayComponent = isCreating
? NewAccountWizard
: ExistingAccountDisplay
+ const loggedInUserWithNotificationArray = {
+ ...loggedInUser,
+ notificationChannel: loggedInUser.notificationChannel.split(',')
+ }
return (
Date: Fri, 12 May 2023 16:20:17 -0400
Subject: [PATCH 09/49] feat(NotificationPrefsPane): Add push notification
option.
---
i18n/en-US.yml | 1 +
i18n/es.yml | 1 +
i18n/fr.yml | 1 +
i18n/ko.yml | 1 +
i18n/vi.yml | 1 +
i18n/zh.yml | 1 +
lib/components/user/notification-prefs-pane.tsx | 14 +++++++++++---
7 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/i18n/en-US.yml b/i18n/en-US.yml
index 959eb6980..5143f007f 100644
--- a/i18n/en-US.yml
+++ b/i18n/en-US.yml
@@ -129,6 +129,7 @@ common:
walk: Walk
notifications:
email: email
+ push: push notifications
sms: SMS
places:
custom: custom
diff --git a/i18n/es.yml b/i18n/es.yml
index 9cfc2d409..238604ce2 100644
--- a/i18n/es.yml
+++ b/i18n/es.yml
@@ -133,6 +133,7 @@ common:
walk: Caminar
notifications:
email: correo electrónico
+ push: notificaciones push
sms: Mensaje de texto
places:
custom: personalizado
diff --git a/i18n/fr.yml b/i18n/fr.yml
index e3bfde8e1..0a600bbb8 100644
--- a/i18n/fr.yml
+++ b/i18n/fr.yml
@@ -137,6 +137,7 @@ common:
walk: À pied
notifications:
email: e-mail
+ push: notifications push
sms: SMS
places:
custom: divers
diff --git a/i18n/ko.yml b/i18n/ko.yml
index 627b4a9de..597d963c1 100644
--- a/i18n/ko.yml
+++ b/i18n/ko.yml
@@ -119,6 +119,7 @@ common:
walk: 걷기
notifications:
email: 이메일
+ push: 푸시 알림
sms: SMS
places:
custom: 사용자 정의
diff --git a/i18n/vi.yml b/i18n/vi.yml
index 7b582ca5c..f9aa6fc98 100644
--- a/i18n/vi.yml
+++ b/i18n/vi.yml
@@ -128,6 +128,7 @@ common:
walk: Đi bộ
notifications:
email: e-mail
+ push: thông báo đẩy
sms: tin nhắn
places:
custom: phong tục
diff --git a/i18n/zh.yml b/i18n/zh.yml
index 59f0f3fec..d61801e44 100644
--- a/i18n/zh.yml
+++ b/i18n/zh.yml
@@ -119,6 +119,7 @@ common:
walk: 步行
notifications:
email: 电子邮件
+ push: 推送通知
sms: 短信
places:
custom: 习俗
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index 2a034c3bd..0804875e8 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -16,6 +16,7 @@ interface Fields {
isPhoneNumberVerified?: boolean
notificationChannel: string
phoneNumber?: string
+ pushDeviceName?: string
}
interface Props extends FormikProps {
@@ -26,7 +27,7 @@ interface Props extends FormikProps {
}
}
-const allowedNotificationChannels = ['email', 'sms']
+const allowedNotificationChannels = ['email', 'sms', 'push']
// Styles
const NotificationOption = styled.div`
@@ -62,7 +63,7 @@ const NotificationPrefsPane = ({
phoneFormatOptions,
values: userData // Formik prop
}: Props): JSX.Element => {
- const { email, isPhoneNumberVerified, phoneNumber } = userData
+ const { email, isPhoneNumberVerified, phoneNumber, pushDeviceName } = userData
return (
@@ -93,7 +94,7 @@ const NotificationPrefsPane = ({
{email}
>
- ) : (
+ ) : type === 'sms' ? (
<>
@@ -107,6 +108,13 @@ const NotificationPrefsPane = ({
phoneFormatOptions={phoneFormatOptions}
/>
>
+ ) : (
+ <>
+
+
+
+ {pushDeviceName}
+ >
)}
From 42f01a70538fd65af0a670ea659170fd616a01a5 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 12 May 2023 16:28:36 -0400
Subject: [PATCH 10/49] improvement(NotificationPrefsPane): Add explanation if
no device has been set for push notifications
---
i18n/en-US.yml | 1 +
i18n/es.yml | 1 +
i18n/fr.yml | 1 +
lib/components/user/notification-prefs-pane.tsx | 8 +++++++-
4 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/i18n/en-US.yml b/i18n/en-US.yml
index 5143f007f..26f9af5a6 100644
--- a/i18n/en-US.yml
+++ b/i18n/en-US.yml
@@ -357,6 +357,7 @@ components:
description: The content you requested is not available.
header: Content not found
NotificationPrefsPane:
+ noDeviceForPush: Register your device using the mobile app to access this setting.
noneSelect: Don't notify me
notificationChannelPrompt: "Receive notifications about your saved trips via:"
notificationEmailDetail: "Notification emails will be sent to:"
diff --git a/i18n/es.yml b/i18n/es.yml
index 238604ce2..883c408a4 100644
--- a/i18n/es.yml
+++ b/i18n/es.yml
@@ -363,6 +363,7 @@ components:
description: El contenido que ha solicitado no está disponible.
header: No se encontró el contenido
NotificationPrefsPane:
+ noDeviceForPush: Regístrese con la aplicación móvil para acceder a esta configuración.
noneSelect: No enviar notificaciones
notificationChannelPrompt: "Recibir notificaciones para sus viajes guardados por :"
notificationEmailDetail: "Los correos electrónicos de notificación se enviarán a:"
diff --git a/i18n/fr.yml b/i18n/fr.yml
index 0a600bbb8..cf133eefe 100644
--- a/i18n/fr.yml
+++ b/i18n/fr.yml
@@ -369,6 +369,7 @@ components:
description: Le contenu que vous avez demandé n'est pas disponible.
header: Contenu introuvable
NotificationPrefsPane:
+ noDeviceForPush: Inscrivez-vous avec l'application mobile pour accéder à ce paramètre.
noneSelect: Ne pas me notifier
notificationChannelPrompt: "Recevoir des notifications sur vos trajets enregistrés par :"
notificationEmailDetail: "Les courriers de notification seront envoyés à :"
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index 0804875e8..a89be00e7 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -80,6 +80,8 @@ const NotificationPrefsPane = ({
- {pushDeviceName}
+
+ {pushDeviceName || (
+
+ )}
+
>
)}
From a6005d3816be30a455e585c08f1a03bf7cca6b39 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 12 May 2023 16:35:24 -0400
Subject: [PATCH 11/49] chore(i18n): Remove unused messages.
---
i18n/en-US.yml | 2 --
i18n/es.yml | 2 --
i18n/fr.yml | 2 --
i18n/ko.yml | 2 --
i18n/vi.yml | 2 --
i18n/zh.yml | 2 --
6 files changed, 12 deletions(-)
diff --git a/i18n/en-US.yml b/i18n/en-US.yml
index 26f9af5a6..d1ee7d1a3 100644
--- a/i18n/en-US.yml
+++ b/i18n/en-US.yml
@@ -358,9 +358,7 @@ components:
header: Content not found
NotificationPrefsPane:
noDeviceForPush: Register your device using the mobile app to access this setting.
- noneSelect: Don't notify me
notificationChannelPrompt: "Receive notifications about your saved trips via:"
- notificationEmailDetail: "Notification emails will be sent to:"
PhoneNumberEditor:
changeNumber: Change number
invalidCode: Please enter 6 digits for the validation code.
diff --git a/i18n/es.yml b/i18n/es.yml
index 883c408a4..dd7f4f833 100644
--- a/i18n/es.yml
+++ b/i18n/es.yml
@@ -364,9 +364,7 @@ components:
header: No se encontró el contenido
NotificationPrefsPane:
noDeviceForPush: Regístrese con la aplicación móvil para acceder a esta configuración.
- noneSelect: No enviar notificaciones
notificationChannelPrompt: "Recibir notificaciones para sus viajes guardados por :"
- notificationEmailDetail: "Los correos electrónicos de notificación se enviarán a:"
PhoneNumberEditor:
changeNumber: Cambiar número de teléfono
invalidCode: Introduzca 6 dígitos para el código de validación.
diff --git a/i18n/fr.yml b/i18n/fr.yml
index cf133eefe..a19401137 100644
--- a/i18n/fr.yml
+++ b/i18n/fr.yml
@@ -370,9 +370,7 @@ components:
header: Contenu introuvable
NotificationPrefsPane:
noDeviceForPush: Inscrivez-vous avec l'application mobile pour accéder à ce paramètre.
- noneSelect: Ne pas me notifier
notificationChannelPrompt: "Recevoir des notifications sur vos trajets enregistrés par :"
- notificationEmailDetail: "Les courriers de notification seront envoyés à :"
PhoneNumberEditor:
changeNumber: Changer de numéro
invalidCode: Le code de vérification doit comporter 6 chiffres.
diff --git a/i18n/ko.yml b/i18n/ko.yml
index 597d963c1..53fa7c86e 100644
--- a/i18n/ko.yml
+++ b/i18n/ko.yml
@@ -336,9 +336,7 @@ components:
description: 요청한 콘텐츠를 사용할 수 없습니다.
header: 콘텐츠를 찾을 수 없음
NotificationPrefsPane:
- noneSelect: 알림 거부
notificationChannelPrompt: "저장된 여행의 알림을 받는 방법:"
- notificationEmailDetail: "알림 이메일이 다음으로 전송됩니다:"
PhoneNumberEditor:
changeNumber: 번호 변경
invalidCode: 확인 코드 6 자리를 입력하세요.
diff --git a/i18n/vi.yml b/i18n/vi.yml
index f9aa6fc98..704c1faff 100644
--- a/i18n/vi.yml
+++ b/i18n/vi.yml
@@ -344,9 +344,7 @@ 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:
- noneSelect: Đừng thông báo cho tôi
notificationChannelPrompt: "Nhận thông báo về các chuyến đi đã lưu bằng:"
- notificationEmailDetail: "Email thông báo sẽ được gửi đến:"
PhoneNumberEditor:
changeNumber: Thay đổi số điện thoại
invalidCode: Vui lòng nhập 6 chữ số cho mã xác thực.
diff --git a/i18n/zh.yml b/i18n/zh.yml
index d61801e44..5805c2cd6 100644
--- a/i18n/zh.yml
+++ b/i18n/zh.yml
@@ -336,9 +336,7 @@ components:
description: 您要求的内容不存在.
header: 未找到内容
NotificationPrefsPane:
- noneSelect: 不要通知我
notificationChannelPrompt: "如何接收已保存行程的通知:"
- notificationEmailDetail: "通知邮件将被发送至:"
PhoneNumberEditor:
changeNumber: 更改电话号码
invalidCode: 请输入6位数的验证码.
From 459fa01f531f27abf9ac7fc8ee2cae347ff4c736 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 18 May 2023 12:33:53 -0400
Subject: [PATCH 12/49] chore(i18n): Tweak wording when no device is
registered.
---
i18n/en-US.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/i18n/en-US.yml b/i18n/en-US.yml
index d1ee7d1a3..03677b927 100644
--- a/i18n/en-US.yml
+++ b/i18n/en-US.yml
@@ -357,7 +357,7 @@ components:
description: The content you requested is not available.
header: Content not found
NotificationPrefsPane:
- noDeviceForPush: Register your device using the mobile app to access this setting.
+ noDeviceForPush: Register your device using the mobile app to access push notifications.
notificationChannelPrompt: "Receive notifications about your saved trips via:"
PhoneNumberEditor:
changeNumber: Change number
From edc4cc8bb941f2b880b4d10dc04bea6c25f66dcd Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 18 May 2023 14:13:14 -0400
Subject: [PATCH 13/49] fix(UserAccountScreen): Send blank string to server if
no notif channels are selected.
---
lib/components/user/user-account-screen.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/lib/components/user/user-account-screen.js b/lib/components/user/user-account-screen.js
index b153f5667..6b05245be 100644
--- a/lib/components/user/user-account-screen.js
+++ b/lib/components/user/user-account-screen.js
@@ -47,7 +47,10 @@ class UserAccountScreen extends Component {
// Convert the notification attributes from array to comma-separated string.
const passedUserData = clone(userData)
const { notificationChannel } = passedUserData
- if (typeof notificationChannel === 'object' && notificationChannel.length) {
+ if (
+ typeof notificationChannel === 'object' &&
+ typeof notificationChannel.length === 'number'
+ ) {
passedUserData.notificationChannel = notificationChannel.join(',')
}
await createOrUpdateUser(passedUserData, silentOnSucceed, intl)
From 14f73d60665c1e8120a91c2455670832c42453c8 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 12 Jul 2023 16:36:25 -0400
Subject: [PATCH 14/49] refactor(NotificationPrefsPane): Adjust push devices
field name
---
lib/components/user/notification-prefs-pane.tsx | 9 ++++++---
lib/components/user/types.ts | 1 +
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index 47db97795..84a691eeb 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -57,7 +57,7 @@ const NotificationPrefsPane = ({
phoneFormatOptions,
values: userData // Formik prop
}: Props): JSX.Element => {
- const { email, isPhoneNumberVerified, phoneNumber, pushDeviceName } = userData
+ const { email, isPhoneNumberVerified, phoneNumber, pushDevices } = userData
return (
@@ -75,7 +75,7 @@ const NotificationPrefsPane = ({
- {pushDeviceName || (
+ {pushDevices ? (
+ // TODO: i18n
+ `${pushDevices} devices registered`
+ ) : (
)}
diff --git a/lib/components/user/types.ts b/lib/components/user/types.ts
index 47c583755..4360052d9 100644
--- a/lib/components/user/types.ts
+++ b/lib/components/user/types.ts
@@ -22,6 +22,7 @@ export interface User {
isPhoneNumberVerified?: boolean
notificationChannel?: string
phoneNumber?: string
+ pushDevices?: number
savedLocations?: UserSavedLocation[]
storeTripHistory?: boolean
}
From 676f1db665068d62b5d2349b96031622a404ff4e Mon Sep 17 00:00:00 2001
From: miles-grant-ibigroup
Date: Thu, 10 Aug 2023 15:47:44 -0400
Subject: [PATCH 15/49] refactor: begin shift from walk reluctance slider to
dropdown
---
.../form/call-taker/advanced-options.js | 28 +++++++++++--------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/lib/components/form/call-taker/advanced-options.js b/lib/components/form/call-taker/advanced-options.js
index 450c8c67f..dcf81ee32 100644
--- a/lib/components/form/call-taker/advanced-options.js
+++ b/lib/components/form/call-taker/advanced-options.js
@@ -2,9 +2,13 @@
// FIXME: Remove the following eslint rule exception.
/* eslint-disable jsx-a11y/label-has-for */
import * as TripFormClasses from '@opentripplanner/trip-form/lib/styled'
+import {
+ DropdownSelector,
+ SliderSelector,
+ SubmodeSelector
+} from '@opentripplanner/trip-form'
import { FormattedMessage, injectIntl } from 'react-intl'
import { hasBike } from '@opentripplanner/core-utils/lib/itinerary'
-import { SliderSelector, SubmodeSelector } from '@opentripplanner/trip-form'
import isEmpty from 'lodash.isempty'
import React, { Component, lazy, Suspense } from 'react'
import styled from 'styled-components'
@@ -155,9 +159,9 @@ class AdvancedOptions extends Component {
})
}
- _setWaklTolerance = ({ walkTolerance }) => {
+ _setWalkTolerance = ({ walkReluctance }) => {
this.props.setUrlSearch({
- walkTolerance
+ walkReluctance
})
}
@@ -224,17 +228,19 @@ class AdvancedOptions extends Component {
justifyContent: 'space-between'
}}
>
-
{hasBike(currentModes?.map((m) => m.mode).join(',') || '') ? (
From a721df410c66ddc6bca8b1658d88154e6a2ecaff Mon Sep 17 00:00:00 2001
From: amy-corson-ibigroup
<115499534+amy-corson-ibigroup@users.noreply.github.com>
Date: Tue, 15 Aug 2023 10:29:35 -0500
Subject: [PATCH 16/49] feat: reset focus to top on each account step
---
lib/components/user/sequential-pane-display.tsx | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/lib/components/user/sequential-pane-display.tsx b/lib/components/user/sequential-pane-display.tsx
index 1939d67af..adf171e21 100644
--- a/lib/components/user/sequential-pane-display.tsx
+++ b/lib/components/user/sequential-pane-display.tsx
@@ -50,6 +50,12 @@ class SequentialPaneDisplay extends Component> {
routeTo(`${parentPath}/${nextId}`)
}
+ h1Ref = React.createRef()
+
+ _handleFocus = () => {
+ this.h1Ref?.current?.focus()
+ }
+
_handleToNextPane = async (e: MouseEvent) => {
const { activePane, activePaneIndex, panes } = this.props
const { invalid, invalidMessage } = activePane
@@ -70,6 +76,7 @@ class SequentialPaneDisplay extends Component> {
this._routeTo(nextId)
}
}
+ this._handleFocus()
}
_handleToPrevPane = () => {
@@ -78,6 +85,11 @@ class SequentialPaneDisplay extends Component> {
const prevId = panes[activePaneIndex - 1].id
prevId && this._routeTo(prevId)
}
+ this._handleFocus()
+ }
+
+ componentDidMount(): void {
+ this._handleFocus()
}
render() {
@@ -86,7 +98,7 @@ class SequentialPaneDisplay extends Component> {
return (
<>
-
+
Date: Tue, 15 Aug 2023 17:02:59 -0400
Subject: [PATCH 17/49] refactor(i18n): Remove unused strings.
---
i18n/en-US.yml | 3 ---
i18n/fr.yml | 5 -----
2 files changed, 8 deletions(-)
diff --git a/i18n/en-US.yml b/i18n/en-US.yml
index d6f6650a3..5abed7019 100644
--- a/i18n/en-US.yml
+++ b/i18n/en-US.yml
@@ -354,11 +354,8 @@ components:
description: The content you requested is not available.
header: Content not found
NotificationPrefsPane:
- description: You can receive notifications about trips you frequently take.
noDeviceForPush: Register your device using the mobile app to access push notifications.
- noneSelect: Don't notify me
notificationChannelPrompt: "Receive notifications about your saved trips via:"
- notificationEmailDetail: "Notification emails will be sent to:"
OTP2ErrorRenderer:
LOCATION_NOT_FOUND:
body: >-
diff --git a/i18n/fr.yml b/i18n/fr.yml
index c6af5b03b..3d2e4afe0 100644
--- a/i18n/fr.yml
+++ b/i18n/fr.yml
@@ -367,13 +367,8 @@ components:
description: Le contenu que vous avez demandé n'est pas disponible.
header: Contenu introuvable
NotificationPrefsPane:
- description: >-
- Vous pouvez recevoir des notifications sur les trajets que vous effectuez
- fréquemment.
noDeviceForPush: Inscrivez-vous avec l'application mobile pour accéder à ce paramètre.
- noneSelect: Ne pas me notifier
notificationChannelPrompt: "Recevoir des notifications sur vos trajets par :"
- notificationEmailDetail: "Les courriers de notification seront envoyés à :"
OTP2ErrorRenderer:
LOCATION_NOT_FOUND:
body: >-
From 51ca633c5bff37b0f5890348bea6882d98a41a29 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 18 Aug 2023 14:10:02 -0400
Subject: [PATCH 18/49] fix(narrative-itineraries): Make sure leg
alernateRoutes available on earliest itin.
---
.../narrative/narrative-itineraries.js | 20 ++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index 2f37581e1..aa78d24a1 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -44,11 +44,16 @@ import NarrativeItinerariesErrors from './narrative-itineraries-errors'
import NarrativeItinerariesHeader from './narrative-itineraries-header'
function doMergeItineraries(itineraries) {
- const mergedItineraries = itineraries
- .reduce((prev, cur, curIndex) => {
+ // Order itineraries by start time.
+ // This is because alternate routes are only added to the first non-duplicate itinerary,
+ // and we show alternate routes for the first (i.e. earliest) non-duplicate itinerary found.
+ const sortedItineraries = sortStartTimes([...itineraries])
+ const mergedItineraries = sortedItineraries
+ .reduce((prev, cur) => {
const updatedItineraries = clone(prev)
const updatedItinerary = clone(cur)
- updatedItinerary.index = curIndex
+ // Sorting itineraries above requires to find the index in the original array.
+ updatedItinerary.index = itineraries.indexOf(cur)
const duplicateIndex = updatedItineraries.findIndex((itin) =>
itinerariesAreEqual(itin, cur)
@@ -91,15 +96,16 @@ function doMergeItineraries(itineraries) {
// This map catches those and stores the alternate routes so they can be displayed
duplicateItin.legs = duplicateItin.legs.map((leg, index) => {
const newLeg = clone(leg)
- if (leg?.routeId !== cur.legs[index]?.routeId) {
+ const curLeg = cur.legs[index]
+ const curLegRouteId = curLeg?.routeId
+ if (curLegRouteId && leg?.routeId && leg?.routeId !== curLegRouteId) {
if (!newLeg.alternateRoutes) {
newLeg.alternateRoutes = {}
}
- const { routeId } = cur.legs?.[index]
- newLeg.alternateRoutes[routeId] = {
+ newLeg.alternateRoutes[curLegRouteId] = {
// We save the entire leg to the alternateRoutes object so in
// the future, we can draw the leg on the map as an alternate route
- ...cur.legs?.[index]
+ ...curLeg
}
}
return newLeg
From fb7f0be2473dc59455c098887d0d4fc3ca8ddd60 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 18 Aug 2023 14:33:58 -0400
Subject: [PATCH 19/49] fix(create-otp-reducer): Unset the visible itin when
setting the active itin.
---
lib/reducers/create-otp-reducer.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/reducers/create-otp-reducer.js b/lib/reducers/create-otp-reducer.js
index bc866f3ea..7b5f1f8e3 100644
--- a/lib/reducers/create-otp-reducer.js
+++ b/lib/reducers/create-otp-reducer.js
@@ -464,7 +464,8 @@ function createOtpReducer(config) {
[state.activeSearchId]: {
activeItinerary: { $set: action.payload.index },
activeLeg: { $set: null },
- activeStep: { $set: null }
+ activeStep: { $set: null },
+ visibleItinerary: { $set: null }
}
}
})
From 52ed414b5a4ad0d3033d566bfacc03336fdf3974 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 18 Aug 2023 14:34:50 -0400
Subject: [PATCH 20/49] refactor(metro-itinerary): Remove unused import.
---
lib/components/narrative/metro/metro-itinerary.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/components/narrative/metro/metro-itinerary.tsx b/lib/components/narrative/metro/metro-itinerary.tsx
index e86a593e3..274b8816c 100644
--- a/lib/components/narrative/metro/metro-itinerary.tsx
+++ b/lib/components/narrative/metro/metro-itinerary.tsx
@@ -28,7 +28,7 @@ import ItineraryBody from '../line-itin/connected-itinerary-body'
import NarrativeItinerary from '../narrative-itinerary'
import SimpleRealtimeAnnotation from '../simple-realtime-annotation'
-import { getFirstTransitLegStop, getFlexAttirbutes } from './attribute-utils'
+import { getFlexAttirbutes } from './attribute-utils'
import DepartureTimesList, {
SetActiveItineraryHandler
} from './departure-times-list'
From 9ae5bfda7a0b9fff321465c130bb0810da4a105c Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 23 Aug 2023 12:20:18 -0400
Subject: [PATCH 21/49] refactor(NotificationPrefsPane): Apply review feedback.
---
i18n/i18n-exceptions.json | 5 ++
.../user/notification-prefs-pane.tsx | 52 +++++++------------
2 files changed, 25 insertions(+), 32 deletions(-)
diff --git a/i18n/i18n-exceptions.json b/i18n/i18n-exceptions.json
index db534b0e4..60f5855cd 100644
--- a/i18n/i18n-exceptions.json
+++ b/i18n/i18n-exceptions.json
@@ -1,5 +1,10 @@
{
"groups": {
+ "common.notifications.*": [
+ "email",
+ "sms",
+ "push"
+ ],
"components.OTP2ErrorRenderer.*.body": [
"LOCATION_NOT_FOUND",
"NO_STOPS_IN_RANGE",
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index 84a691eeb..3636dedec 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -83,41 +83,29 @@ const NotificationPrefsPane = ({
/>
+
+
+
{type === 'email' ? (
- <>
-
-
-
- {email}
- >
+ {email}
) : type === 'sms' ? (
- <>
-
-
-
-
- >
+
) : (
- <>
-
-
-
-
- {pushDevices ? (
- // TODO: i18n
- `${pushDevices} devices registered`
- ) : (
-
- )}
-
- >
+
+ {pushDevices ? (
+ // TODO: i18n
+ `${pushDevices} devices registered`
+ ) : (
+
+ )}
+
)}
From cddbd028b30f028063551765627b7e9aa011f922 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 23 Aug 2023 12:39:50 -0400
Subject: [PATCH 22/49] refactor(TripNotificationsPane): Enumerate selected
notif channels.
---
.../trip-notifications-pane.tsx | 32 ++++++++++---------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/lib/components/user/monitored-trip/trip-notifications-pane.tsx b/lib/components/user/monitored-trip/trip-notifications-pane.tsx
index 1428b8c22..50145d780 100644
--- a/lib/components/user/monitored-trip/trip-notifications-pane.tsx
+++ b/lib/components/user/monitored-trip/trip-notifications-pane.tsx
@@ -1,7 +1,7 @@
import { Alert, FormControl } from 'react-bootstrap'
import { ExclamationTriangle } from '@styled-icons/fa-solid/ExclamationTriangle'
import { Field, FormikProps } from 'formik'
-import { FormattedMessage, IntlShape, useIntl } from 'react-intl'
+import { FormattedList, FormattedMessage, IntlShape, useIntl } from 'react-intl'
import React, { Component, ComponentType, FormEvent, ReactNode } from 'react'
import styled from 'styled-components'
@@ -179,7 +179,8 @@ class TripNotificationsPane extends Component {
render(): JSX.Element {
const { notificationChannel, values } = this.props
- const areNotificationsDisabled = notificationChannel === 'none'
+ const areNotificationsDisabled =
+ notificationChannel === 'none' || !notificationChannel?.length
// Define a common trip delay field for simplicity, set to the smallest between the
// retrieved departure/arrival delay attributes.
const commonDelayThreshold = Math.min(
@@ -204,24 +205,25 @@ class TripNotificationsPane extends Component {
)
} else {
+ const selectedChannels = notificationChannel
+ .split(',')
+ .filter((channel) => channel?.length)
+ .map((channel) => (
+
+ ))
notificationSettingsContent = (
- )
- }
- : {
- channel: (
-
- )
- }
- }
+ values={{
+ channel: (
+
+ )
+ }}
/>
From 841feb5977e50b636f723aac8db7441836b94c01 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 23 Aug 2023 16:11:49 -0400
Subject: [PATCH 23/49] fix(narrative-itineraries): Find earliest itin of a
group without pre-sorting itins
This preserves the itinerary sort feature.
---
.../narrative/narrative-itineraries.js | 39 ++++++++++++-------
1 file changed, 24 insertions(+), 15 deletions(-)
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index aa78d24a1..ee61416c9 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -44,16 +44,11 @@ import NarrativeItinerariesErrors from './narrative-itineraries-errors'
import NarrativeItinerariesHeader from './narrative-itineraries-header'
function doMergeItineraries(itineraries) {
- // Order itineraries by start time.
- // This is because alternate routes are only added to the first non-duplicate itinerary,
- // and we show alternate routes for the first (i.e. earliest) non-duplicate itinerary found.
- const sortedItineraries = sortStartTimes([...itineraries])
- const mergedItineraries = sortedItineraries
- .reduce((prev, cur) => {
+ const mergedItineraries = itineraries
+ .reduce((prev, cur, curIndex) => {
const updatedItineraries = clone(prev)
const updatedItinerary = clone(cur)
- // Sorting itineraries above requires to find the index in the original array.
- updatedItinerary.index = itineraries.indexOf(cur)
+ updatedItinerary.index = curIndex
const duplicateIndex = updatedItineraries.findIndex((itin) =>
itinerariesAreEqual(itin, cur)
@@ -65,10 +60,23 @@ function doMergeItineraries(itineraries) {
// Only process itineraries less than 24 hours in the future
differenceInDays(updatedItinerary.startTime, Date.now()) < 1
) {
- const duplicateItin = updatedItineraries[duplicateIndex]
+ const duplicateFoundItin = updatedItineraries[duplicateIndex]
// TODO: MERGE ROUTE NAMES
- // Add only new start time to existing itinerary
+ // Add only new start time to existing itinerary.
+ // The existing itinerary is the earliest between
+ // this itinerary (updatedItinerary) and duplicateItin.
+ // This is because alternate routes are only added to the first non-duplicate itinerary,
+ // and we show alternate routes for the first (i.e. earliest) non-duplicate itinerary found.
+ let duplicateItin = duplicateFoundItin
+ let itinCopyToAdd = updatedItinerary
+ if (duplicateFoundItin.startTime > updatedItinerary.startTime) {
+ duplicateItin = updatedItinerary
+ duplicateItin.startTimes = duplicateFoundItin.allStartTimes
+ updatedItineraries[duplicateIndex] = updatedItinerary
+ itinCopyToAdd = duplicateFoundItin
+ }
+
if (!duplicateItin.allStartTimes) {
duplicateItin.allStartTimes = [
{
@@ -82,13 +90,14 @@ function doMergeItineraries(itineraries) {
// the uniqueness feature of Set, but unfortunately objects are never equal
if (
!duplicateItin.allStartTimes.find(
- (time) => getFirstLegStartTime(time.legs) === cur.startTime
+ (time) =>
+ getFirstLegStartTime(time.legs) === itinCopyToAdd.startTime
)
) {
duplicateItin.allStartTimes.push({
- itinerary: updatedItinerary,
- legs: cur.legs,
- realtime: firstTransitLegIsRealtime(cur)
+ itinerary: itinCopyToAdd,
+ legs: itinCopyToAdd.legs,
+ realtime: firstTransitLegIsRealtime(itinCopyToAdd)
})
}
@@ -96,7 +105,7 @@ function doMergeItineraries(itineraries) {
// This map catches those and stores the alternate routes so they can be displayed
duplicateItin.legs = duplicateItin.legs.map((leg, index) => {
const newLeg = clone(leg)
- const curLeg = cur.legs[index]
+ const curLeg = itinCopyToAdd.legs[index]
const curLegRouteId = curLeg?.routeId
if (curLegRouteId && leg?.routeId && leg?.routeId !== curLegRouteId) {
if (!newLeg.alternateRoutes) {
From 2040a8fc7b08e49352fa973dd1669e5ac2564004 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 23 Aug 2023 16:23:23 -0400
Subject: [PATCH 24/49] refactor(attribute-utils): Fix typo in flex function
name.
---
lib/components/narrative/metro/attribute-utils.tsx | 2 +-
lib/components/narrative/metro/metro-itinerary.tsx | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/components/narrative/metro/attribute-utils.tsx b/lib/components/narrative/metro/attribute-utils.tsx
index 36a12b90b..c48afd0c8 100644
--- a/lib/components/narrative/metro/attribute-utils.tsx
+++ b/lib/components/narrative/metro/attribute-utils.tsx
@@ -9,7 +9,7 @@ export const getFirstTransitLegStop = (
itinerary.legs?.find((leg: Leg) => leg?.from?.vertexType === 'TRANSIT')?.from
?.name
-export const getFlexAttirbutes = (
+export const getFlexAttributes = (
itinerary: Itinerary
): {
isCallAhead: boolean
diff --git a/lib/components/narrative/metro/metro-itinerary.tsx b/lib/components/narrative/metro/metro-itinerary.tsx
index 274b8816c..26ffa98a6 100644
--- a/lib/components/narrative/metro/metro-itinerary.tsx
+++ b/lib/components/narrative/metro/metro-itinerary.tsx
@@ -28,7 +28,7 @@ import ItineraryBody from '../line-itin/connected-itinerary-body'
import NarrativeItinerary from '../narrative-itinerary'
import SimpleRealtimeAnnotation from '../simple-realtime-annotation'
-import { getFlexAttirbutes } from './attribute-utils'
+import { getFlexAttributes } from './attribute-utils'
import DepartureTimesList, {
SetActiveItineraryHandler
} from './departure-times-list'
@@ -266,7 +266,7 @@ class MetroItinerary extends NarrativeItinerary {
const { SvgIcon } = this.context
const { isCallAhead, isContinuousDropoff, isFlexItinerary, phone } =
- getFlexAttirbutes(itinerary)
+ getFlexAttributes(itinerary)
const { fareCurrency, transitFare } = getFare(itinerary, defaultFareType)
From 370dadf3c9999a2ec9ce3a7d724837090bf9b3ad Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 23 Aug 2023 16:30:38 -0400
Subject: [PATCH 25/49] refactor(narrative-itineraries): Extract makeStartTime
method.
---
.../narrative/narrative-itineraries.js | 23 +++++++++----------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index ee61416c9..d5a7b0f2f 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -43,6 +43,15 @@ import Loading from './loading'
import NarrativeItinerariesErrors from './narrative-itineraries-errors'
import NarrativeItinerariesHeader from './narrative-itineraries-header'
+/** Creates a start time object for the given itinerary. */
+function makeStartTime(itinerary) {
+ return {
+ itinerary,
+ legs: itinerary.legs,
+ realtime: firstTransitLegIsRealtime(itinerary)
+ }
+}
+
function doMergeItineraries(itineraries) {
const mergedItineraries = itineraries
.reduce((prev, cur, curIndex) => {
@@ -78,13 +87,7 @@ function doMergeItineraries(itineraries) {
}
if (!duplicateItin.allStartTimes) {
- duplicateItin.allStartTimes = [
- {
- itinerary: duplicateItin,
- legs: duplicateItin.legs,
- realtime: firstTransitLegIsRealtime(duplicateItin)
- }
- ]
+ duplicateItin.allStartTimes = [makeStartTime(duplicateItin)]
}
// Only add new time if it doesn't already exist. It would be better to use
// the uniqueness feature of Set, but unfortunately objects are never equal
@@ -94,11 +97,7 @@ function doMergeItineraries(itineraries) {
getFirstLegStartTime(time.legs) === itinCopyToAdd.startTime
)
) {
- duplicateItin.allStartTimes.push({
- itinerary: itinCopyToAdd,
- legs: itinCopyToAdd.legs,
- realtime: firstTransitLegIsRealtime(itinCopyToAdd)
- })
+ duplicateItin.allStartTimes.push(makeStartTime(itinCopyToAdd))
}
// Some legs will be the same, but have a different route
From 87cc55f79aca73ea6a1a9d5e8cce3ffbfe9943fa Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 25 Aug 2023 16:12:04 -0400
Subject: [PATCH 26/49] refactor(route-details): Make light refactors to
component.
---
lib/components/viewers/route-details.js | 36 +++++++++++--------------
1 file changed, 16 insertions(+), 20 deletions(-)
diff --git a/lib/components/viewers/route-details.js b/lib/components/viewers/route-details.js
index b3d7099f3..faf32780e 100644
--- a/lib/components/viewers/route-details.js
+++ b/lib/components/viewers/route-details.js
@@ -3,10 +3,9 @@
import { connect } from 'react-redux'
import { FormattedMessage, injectIntl } from 'react-intl'
import { getMostReadableTextColor } from '@opentripplanner/core-utils/lib/route'
-
-import { LinkOpensNewWindow } from '../util/externalLink'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
+import styled from 'styled-components'
import {
extractHeadsignFromPattern,
@@ -14,7 +13,10 @@ import {
} from '../../util/viewer'
import { findStopsForPattern } from '../../actions/api'
import { getOperatorName } from '../../util/state'
+import { LinkOpensNewWindow } from '../util/externalLink'
import { setHoveredStop, setViewedRoute, setViewedStop } from '../../actions/ui'
+import { SortResultsDropdown } from '../util/dropdown'
+import { UnstyledButton } from '../util/unstyled-button'
import {
Container,
@@ -26,10 +28,14 @@ import {
StopContainer,
StopLink
} from './styled'
-import { SortResultsDropdown } from '../util/dropdown'
-import { UnstyledButton } from '../util/unstyled-button'
-import styled from 'styled-components'
+const PatternSelectButton = styled(UnstyledButton)`
+ span {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+`
class RouteDetails extends Component {
static propTypes = {
@@ -80,24 +86,14 @@ class RouteDetails extends Component {
const routeColor = getRouteColorBasedOnSettings(operator, route)
- const PatternSelectButton = styled(UnstyledButton)`
- span {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- `
-
const headsigns =
patterns &&
Object.entries(patterns)
- .map((pattern) => {
- return {
- geometryLength: pattern[1].geometry?.length,
- headsign: extractHeadsignFromPattern(pattern[1], shortName),
- id: pattern[0]
- }
- })
+ .map(([id, pattern]) => ({
+ geometryLength: pattern.geometry?.length,
+ headsign: extractHeadsignFromPattern(pattern, shortName),
+ id
+ }))
// Remove duplicate headsigns. Using a reducer means that the first pattern
// with a specific headsign is the accepted one. TODO: is this good behavior?
.reduce((prev, cur) => {
From 3623041d06558e7bef41a6bfdf735a99cdf4a5bd Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 25 Aug 2023 16:42:17 -0400
Subject: [PATCH 27/49] fix(route-details): Obtain diplayed pattern name from
orginal pattern dictionary.
---
lib/components/viewers/route-details.js | 101 +++++++++++-------------
1 file changed, 44 insertions(+), 57 deletions(-)
diff --git a/lib/components/viewers/route-details.js b/lib/components/viewers/route-details.js
index faf32780e..7877f9681 100644
--- a/lib/components/viewers/route-details.js
+++ b/lib/components/viewers/route-details.js
@@ -80,62 +80,58 @@ class RouteDetails extends Component {
}
render() {
- const { intl, operator, pattern, route, setHoveredStop, viewedRoute } =
- this.props
- const { agency, patterns, shortName, url } = route
+ const { intl, operator, pattern, route, setHoveredStop } = this.props
+ const { agency, patterns = {}, shortName, url } = route
const routeColor = getRouteColorBasedOnSettings(operator, route)
- const headsigns =
- patterns &&
- Object.entries(patterns)
- .map(([id, pattern]) => ({
- geometryLength: pattern.geometry?.length,
- headsign: extractHeadsignFromPattern(pattern, shortName),
- id
- }))
- // Remove duplicate headsigns. Using a reducer means that the first pattern
- // with a specific headsign is the accepted one. TODO: is this good behavior?
- .reduce((prev, cur) => {
- const amended = prev
- const alreadyExistingIndex = prev.findIndex(
- (h) => h.headsign === cur.headsign
- )
- // If the item we're replacing has less geometry, replace it!
- if (alreadyExistingIndex >= 0) {
- // Only replace if new pattern has greater geometry
- if (
- amended[alreadyExistingIndex].geometryLength < cur.geometryLength
- ) {
- amended[alreadyExistingIndex] = cur
- }
- } else {
- amended.push(cur)
+ const headsigns = Object.entries(patterns)
+ .map(([id, pat]) => ({
+ geometryLength: pat.geometry?.length,
+ headsign: extractHeadsignFromPattern(pat, shortName),
+ id
+ }))
+ // Remove duplicate headsigns. Using a reducer means that the first pattern
+ // with a specific headsign is the accepted one. TODO: is this good behavior?
+ .reduce((prev, cur) => {
+ const amended = prev
+ const alreadyExistingIndex = prev.findIndex(
+ (h) => h.headsign === cur.headsign
+ )
+ // If the item we're replacing has less geometry, replace it!
+ if (alreadyExistingIndex >= 0) {
+ // Only replace if new pattern has greater geometry
+ if (
+ amended[alreadyExistingIndex].geometryLength < cur.geometryLength
+ ) {
+ amended[alreadyExistingIndex] = cur
}
- return amended
- }, [])
- .sort((a, b) => {
- // sort by number of vehicles on that pattern
- const aVehicleCount = route.vehicles?.filter(
- (vehicle) => vehicle.patternId === a.id
- ).length
- const bVehicleCount = route.vehicles?.filter(
- (vehicle) => vehicle.patternId === b.id
- ).length
-
- // if both have the same count, sort by pattern geometry length
- if (aVehicleCount === bVehicleCount) {
- return b.geometryLength - a.geometryLength
- }
- return bVehicleCount - aVehicleCount
- })
+ } else {
+ amended.push(cur)
+ }
+ return amended
+ }, [])
+ .sort((a, b) => {
+ // sort by number of vehicles on that pattern
+ const aVehicleCount = route.vehicles?.filter(
+ (vehicle) => vehicle.patternId === a.id
+ ).length
+ const bVehicleCount = route.vehicles?.filter(
+ (vehicle) => vehicle.patternId === b.id
+ ).length
+
+ // if both have the same count, sort by pattern geometry length
+ if (aVehicleCount === bVehicleCount) {
+ return b.geometryLength - a.geometryLength
+ }
+ return bVehicleCount - aVehicleCount
+ })
const patternSelectLabel = intl.formatMessage({
id: 'components.RouteDetails.selectADirection'
})
const patternSelectName =
- headsigns?.find((h) => h.id === viewedRoute?.patternId)?.headsign ||
- patternSelectLabel
+ (pattern && patterns[pattern.id]?.headsign) || patternSelectLabel
// if no pattern is set, we are in the routeRow
return (
@@ -246,12 +242,6 @@ class RouteDetails extends Component {
}
// connect to redux store
-const mapStateToProps = (state) => {
- return {
- viewedRoute: state.otp.ui.viewedRoute
- }
-}
-
const mapDispatchToProps = {
findStopsForPattern,
setHoveredStop,
@@ -259,7 +249,4 @@ const mapDispatchToProps = {
setViewedStop
}
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(injectIntl(RouteDetails))
+export default connect(null, mapDispatchToProps)(injectIntl(RouteDetails))
From 612933a3b6f114ca6445ca81018cb7176f9aa721 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 25 Aug 2023 16:54:01 -0400
Subject: [PATCH 28/49] refactor(Rename props, remove dead code.):
---
lib/components/viewers/pattern-viewer.tsx | 6 +----
lib/components/viewers/route-details.js | 33 +++++++----------------
2 files changed, 10 insertions(+), 29 deletions(-)
diff --git a/lib/components/viewers/pattern-viewer.tsx b/lib/components/viewers/pattern-viewer.tsx
index 62102089e..1f6204633 100644
--- a/lib/components/viewers/pattern-viewer.tsx
+++ b/lib/components/viewers/pattern-viewer.tsx
@@ -131,11 +131,7 @@ const PatternViewer = ({
-
+
)
}
diff --git a/lib/components/viewers/route-details.js b/lib/components/viewers/route-details.js
index 7877f9681..48ba77c02 100644
--- a/lib/components/viewers/route-details.js
+++ b/lib/components/viewers/route-details.js
@@ -7,14 +7,13 @@ import PropTypes from 'prop-types'
import React, { Component } from 'react'
import styled from 'styled-components'
+import * as uiActions from '../../actions/ui'
import {
extractHeadsignFromPattern,
getRouteColorBasedOnSettings
} from '../../util/viewer'
-import { findStopsForPattern } from '../../actions/api'
import { getOperatorName } from '../../util/state'
import { LinkOpensNewWindow } from '../util/externalLink'
-import { setHoveredStop, setViewedRoute, setViewedStop } from '../../actions/ui'
import { SortResultsDropdown } from '../util/dropdown'
import { UnstyledButton } from '../util/unstyled-button'
@@ -39,27 +38,14 @@ const PatternSelectButton = styled(UnstyledButton)`
class RouteDetails extends Component {
static propTypes = {
- findStopsForPattern: findStopsForPattern.type,
operator: PropTypes.shape({
defaultRouteColor: PropTypes.string,
defaultRouteTextColor: PropTypes.string,
longNameSplitter: PropTypes.string
}),
// There are more items in pattern and route, but none mandatory
- pattern: PropTypes.shape({ id: PropTypes.string }),
- route: PropTypes.shape({ id: PropTypes.string }),
- setHoveredStop: setHoveredStop.type,
- setViewedRoute: setViewedRoute.type
- }
-
- /**
- * Requests stop list for current pattern
- */
- getStops = () => {
- const { findStopsForPattern, pattern, route } = this.props
- if (pattern && route) {
- findStopsForPattern({ patternId: pattern.id, routeId: route.id })
- }
+ patternId: PropTypes.string,
+ route: PropTypes.shape({ id: PropTypes.string })
}
/**
@@ -80,8 +66,9 @@ class RouteDetails extends Component {
}
render() {
- const { intl, operator, pattern, route, setHoveredStop } = this.props
+ const { intl, operator, patternId, route, setHoveredStop } = this.props
const { agency, patterns = {}, shortName, url } = route
+ const pattern = patterns[patternId]
const routeColor = getRouteColorBasedOnSettings(operator, route)
@@ -130,8 +117,7 @@ class RouteDetails extends Component {
const patternSelectLabel = intl.formatMessage({
id: 'components.RouteDetails.selectADirection'
})
- const patternSelectName =
- (pattern && patterns[pattern.id]?.headsign) || patternSelectLabel
+ const patternSelectName = pattern?.headsign || patternSelectLabel
// if no pattern is set, we are in the routeRow
return (
@@ -243,10 +229,9 @@ class RouteDetails extends Component {
// connect to redux store
const mapDispatchToProps = {
- findStopsForPattern,
- setHoveredStop,
- setViewedRoute,
- setViewedStop
+ setHoveredStop: uiActions.setHoveredStop,
+ setViewedRoute: uiActions.setViewedRoute,
+ setViewedStop: uiActions.setViewedStop
}
export default connect(null, mapDispatchToProps)(injectIntl(RouteDetails))
From b64304ac57a73cef88bc32909d95ea3ba15de810 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 25 Aug 2023 18:09:52 -0400
Subject: [PATCH 29/49] refactor(route-details): Convert to TypeScript, add
missing types.
---
lib/components/util/types.ts | 30 ++++----
.../{route-details.js => route-details.tsx} | 72 +++++++++++--------
.../viewers/{styled.js => styled.ts} | 16 +++--
3 files changed, 69 insertions(+), 49 deletions(-)
rename lib/components/viewers/{route-details.js => route-details.tsx} (83%)
rename lib/components/viewers/{styled.js => styled.ts} (89%)
diff --git a/lib/components/util/types.ts b/lib/components/util/types.ts
index d75469556..febaa585d 100644
--- a/lib/components/util/types.ts
+++ b/lib/components/util/types.ts
@@ -1,3 +1,5 @@
+import { Route } from '@opentripplanner/types'
+
// TYPESCRIPT TODO: move this to a larger shared types file, preferably within otp-ui
export interface StopData {
bikeRental: BikeRental
@@ -22,15 +24,6 @@ export interface BikeRental {
stations: any[]
}
-export interface Route {
- agencyId: string
- agencyName: string
- id: string
- longName: string
- mode: string
- sortOrder: number
-}
-
// FIXME: incomplete
export interface StopTime {
departureDelay: number
@@ -45,6 +38,11 @@ export interface Pattern {
desc: string
headsign: string
id: string
+ patternGeometry?: {
+ length: number
+ points: string
+ }
+ stops?: StopData[]
}
export interface Time {
@@ -80,14 +78,18 @@ export interface ViewedRouteState {
routeId: string
}
+export interface RouteVehicle {
+ patternId: string
+}
+
// Routes have many properties beside id, but none of these are guaranteed.
-export interface ViewedRouteObject {
- id: string
- longName?: string
+export interface ViewedRouteObject extends Route {
patterns?: Record
pending?: boolean
- shortName?: string
- textColor?: string
+ url?: string
+ vehicles?: RouteVehicle[]
}
export type SetViewedRouteHandler = (route?: ViewedRouteState) => void
+
+export type SetViewedStopHandler = (payload: { stopId: string }) => void
diff --git a/lib/components/viewers/route-details.js b/lib/components/viewers/route-details.tsx
similarity index 83%
rename from lib/components/viewers/route-details.js
rename to lib/components/viewers/route-details.tsx
index 48ba77c02..2dbc4e3fe 100644
--- a/lib/components/viewers/route-details.js
+++ b/lib/components/viewers/route-details.tsx
@@ -1,9 +1,7 @@
-// FIXME: typescript
-/* eslint-disable react/prop-types */
import { connect } from 'react-redux'
-import { FormattedMessage, injectIntl } from 'react-intl'
+import { FormattedMessage, injectIntl, IntlShape } from 'react-intl'
import { getMostReadableTextColor } from '@opentripplanner/core-utils/lib/route'
-import PropTypes from 'prop-types'
+import { TransitOperator } from '@opentripplanner/types'
import React, { Component } from 'react'
import styled from 'styled-components'
@@ -14,6 +12,11 @@ import {
} from '../../util/viewer'
import { getOperatorName } from '../../util/state'
import { LinkOpensNewWindow } from '../util/externalLink'
+import {
+ SetViewedRouteHandler,
+ SetViewedStopHandler,
+ ViewedRouteObject
+} from '../util/types'
import { SortResultsDropdown } from '../util/dropdown'
import { UnstyledButton } from '../util/unstyled-button'
@@ -36,23 +39,28 @@ const PatternSelectButton = styled(UnstyledButton)`
}
`
-class RouteDetails extends Component {
- static propTypes = {
- operator: PropTypes.shape({
- defaultRouteColor: PropTypes.string,
- defaultRouteTextColor: PropTypes.string,
- longNameSplitter: PropTypes.string
- }),
- // There are more items in pattern and route, but none mandatory
- patternId: PropTypes.string,
- route: PropTypes.shape({ id: PropTypes.string })
- }
+interface PatternSummary {
+ geometryLength: number
+ headsign: string
+ id: string
+}
+
+interface Props {
+ intl: IntlShape
+ operator: TransitOperator
+ patternId: string
+ route: ViewedRouteObject
+ setHoveredStop: (id: string | null) => void
+ setViewedRoute: SetViewedRouteHandler
+ setViewedStop: SetViewedStopHandler
+}
+class RouteDetails extends Component {
/**
* If a headsign link is clicked, set that pattern in redux state so that the
* view can adjust
*/
- _headSignButtonClicked = (id) => {
+ _headSignButtonClicked = (id: string) => {
const { route, setViewedRoute } = this.props
setViewedRoute({ patternId: id, routeId: route.id })
}
@@ -60,7 +68,7 @@ class RouteDetails extends Component {
/**
* If a stop link is clicked, redirect to stop viewer
*/
- _stopLinkClicked = (stopId) => {
+ _stopLinkClicked = (stopId: string) => {
const { setViewedStop } = this.props
setViewedStop({ stopId })
}
@@ -73,14 +81,16 @@ class RouteDetails extends Component {
const routeColor = getRouteColorBasedOnSettings(operator, route)
const headsigns = Object.entries(patterns)
- .map(([id, pat]) => ({
- geometryLength: pat.geometry?.length,
- headsign: extractHeadsignFromPattern(pat, shortName),
- id
- }))
+ .map(
+ ([id, pat]): PatternSummary => ({
+ geometryLength: pat.patternGeometry?.length || 0,
+ headsign: extractHeadsignFromPattern(pat, shortName),
+ id
+ })
+ )
// Remove duplicate headsigns. Using a reducer means that the first pattern
// with a specific headsign is the accepted one. TODO: is this good behavior?
- .reduce((prev, cur) => {
+ .reduce((prev: PatternSummary[], cur) => {
const amended = prev
const alreadyExistingIndex = prev.findIndex(
(h) => h.headsign === cur.headsign
@@ -100,12 +110,12 @@ class RouteDetails extends Component {
}, [])
.sort((a, b) => {
// sort by number of vehicles on that pattern
- const aVehicleCount = route.vehicles?.filter(
- (vehicle) => vehicle.patternId === a.id
- ).length
- const bVehicleCount = route.vehicles?.filter(
- (vehicle) => vehicle.patternId === b.id
- ).length
+ const aVehicleCount =
+ route.vehicles?.filter((vehicle) => vehicle.patternId === a.id)
+ .length || 0
+ const bVehicleCount =
+ route.vehicles?.filter((vehicle) => vehicle.patternId === b.id)
+ .length || 0
// if both have the same count, sort by pattern geometry length
if (aVehicleCount === bVehicleCount) {
@@ -164,7 +174,7 @@ class RouteDetails extends Component {
pullRight
style={{ color: 'black' }}
>
- {headsigns.map((h) => (
+ {headsigns.map((h: PatternSummary) => (
this._headSignButtonClicked(h.id)}
@@ -182,7 +192,7 @@ class RouteDetails extends Component {
diff --git a/lib/components/viewers/styled.js b/lib/components/viewers/styled.ts
similarity index 89%
rename from lib/components/viewers/styled.js
rename to lib/components/viewers/styled.ts
index e1a4bd984..16bfbe173 100644
--- a/lib/components/viewers/styled.js
+++ b/lib/components/viewers/styled.ts
@@ -1,7 +1,14 @@
import styled from 'styled-components'
+interface RenderProps {
+ backgroundColor?: string
+ full?: boolean
+ routeColor?: string
+ textColor?: string
+}
+
/** Route Details */
-export const Container = styled.div`
+export const Container = styled.div`
background-color: ${(props) =>
props.full ? props.backgroundColor || '#ddd' : 'inherit'};
color: ${(props) => (props.full ? props.textColor : 'inherit')};
@@ -60,7 +67,7 @@ export const PatternContainer = styled.div`
}
`
-export const StopContainer = styled.ol`
+export const StopContainer = styled.ol`
color: ${(props) => props?.textColor || '#333'};
background-color: ${(props) => props?.backgroundColor || '#fff'};
overflow-y: scroll;
@@ -69,7 +76,7 @@ export const StopContainer = styled.ol`
are shown when browsers don't calculate 100% sensibly */
padding: 15px 0 100px;
`
-export const StopLink = styled.button`
+export const StopLink = styled.button`
color: ${(props) => props?.textColor + 'da' || '#333'};
background-color: transparent;
border: none;
@@ -82,7 +89,8 @@ export const StopLink = styled.button`
text-decoration: underline;
}
`
-export const Stop = styled.li`
+
+export const Stop = styled.li`
cursor: pointer;
display: block;
white-space: nowrap;
From dba0955402098006461e32b18082a386c9fa498a Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Mon, 28 Aug 2023 10:16:22 -0400
Subject: [PATCH 30/49] refactor(route-details): Use logic to determine
headsign with pattern.
---
lib/components/viewers/route-details.tsx | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/components/viewers/route-details.tsx b/lib/components/viewers/route-details.tsx
index 2dbc4e3fe..f5ee0d53c 100644
--- a/lib/components/viewers/route-details.tsx
+++ b/lib/components/viewers/route-details.tsx
@@ -127,7 +127,9 @@ class RouteDetails extends Component {
const patternSelectLabel = intl.formatMessage({
id: 'components.RouteDetails.selectADirection'
})
- const patternSelectName = pattern?.headsign || patternSelectLabel
+
+ const patternSelectName =
+ extractHeadsignFromPattern(pattern, shortName) || patternSelectLabel
// if no pattern is set, we are in the routeRow
return (
From af56ed50d15a03d667a13000b2fd77e073cdcb2f Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Mon, 28 Aug 2023 10:30:44 -0400
Subject: [PATCH 31/49] fix(route-details): Use index as key in stop list.
---
lib/components/viewers/route-details.tsx | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/lib/components/viewers/route-details.tsx b/lib/components/viewers/route-details.tsx
index f5ee0d53c..4c0524b63 100644
--- a/lib/components/viewers/route-details.tsx
+++ b/lib/components/viewers/route-details.tsx
@@ -129,7 +129,8 @@ class RouteDetails extends Component {
})
const patternSelectName =
- extractHeadsignFromPattern(pattern, shortName) || patternSelectLabel
+ (pattern ? extractHeadsignFromPattern(pattern, shortName) : null) ||
+ patternSelectLabel
// if no pattern is set, we are in the routeRow
return (
@@ -205,9 +206,10 @@ class RouteDetails extends Component {
onMouseLeave={() => setHoveredStop(null)}
textColor={getMostReadableTextColor(routeColor, route?.textColor)}
>
- {pattern?.stops?.map((stop) => (
+ {pattern?.stops?.map((stop, index) => (
this._stopLinkClicked(stop.id)}
onFocus={() => setHoveredStop(stop.id)}
onMouseOver={() => setHoveredStop(stop.id)}
From 85527a4296723f9b0de3bf3d80a23ba5b51cd718 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Mon, 28 Aug 2023 11:29:12 -0400
Subject: [PATCH 32/49] refactor(route-details): Tweak a11y and headsign
lookup.
---
lib/components/viewers/route-details.tsx | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/lib/components/viewers/route-details.tsx b/lib/components/viewers/route-details.tsx
index 4c0524b63..579e376cc 100644
--- a/lib/components/viewers/route-details.tsx
+++ b/lib/components/viewers/route-details.tsx
@@ -129,10 +129,9 @@ class RouteDetails extends Component {
})
const patternSelectName =
- (pattern ? extractHeadsignFromPattern(pattern, shortName) : null) ||
+ headsigns.find((h) => h.id === pattern?.id)?.headsign ||
patternSelectLabel
- // if no pattern is set, we are in the routeRow
return (
{
// Use array index instead of stop id because a stop can be visited several times.
key={index}
onClick={() => this._stopLinkClicked(stop.id)}
- onFocus={() => setHoveredStop(stop.id)}
onMouseOver={() => setHoveredStop(stop.id)}
routeColor={
routeColor.includes('ffffff') ? '#333' : routeColor
@@ -224,6 +222,7 @@ class RouteDetails extends Component {
this._stopLinkClicked(stop.id)}
+ onFocus={() => setHoveredStop(stop.id)}
textColor={getMostReadableTextColor(
routeColor,
route?.textColor
From 257cac2f40ce5533e1d11b34c5efe731b4f16372 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Mon, 28 Aug 2023 17:17:12 -0400
Subject: [PATCH 33/49] fix(metro-itinerary): Display all routes in dashed
lines on mouse leave.
---
lib/components/narrative/metro/metro-itinerary.tsx | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/lib/components/narrative/metro/metro-itinerary.tsx b/lib/components/narrative/metro/metro-itinerary.tsx
index 26ffa98a6..4e65c966d 100644
--- a/lib/components/narrative/metro/metro-itinerary.tsx
+++ b/lib/components/narrative/metro/metro-itinerary.tsx
@@ -202,23 +202,17 @@ class MetroItinerary extends NarrativeItinerary {
static ModesAndRoutes = MetroItineraryRoutes
_onMouseEnter = () => {
- const { active, index, setVisibleItinerary, visibleItinerary } = this.props
+ const { active, index, setVisibleItinerary, visible } = this.props
// Set this itinerary as visible if not already visible.
- const visibleNotSet =
- visibleItinerary === null || visibleItinerary === undefined
- const isVisible =
- visibleItinerary === index || (active === index && visibleNotSet)
+ const isVisible = visible || active === index
if (typeof setVisibleItinerary === 'function' && !isVisible) {
setVisibleItinerary({ index })
}
}
_onMouseLeave = () => {
- const { index, setVisibleItinerary, visibleItinerary } = this.props
- if (
- typeof setVisibleItinerary === 'function' &&
- visibleItinerary === index
- ) {
+ const { setVisibleItinerary, visible } = this.props
+ if (typeof setVisibleItinerary === 'function' && visible) {
setVisibleItinerary({ index: null })
}
}
From c23143a4deca538286356e02284e882f20d8c682 Mon Sep 17 00:00:00 2001
From: Daniel Heppner
Date: Mon, 28 Aug 2023 14:53:40 -0700
Subject: [PATCH 34/49] deps: update new walkspeed deps
---
lib/reducers/create-otp-reducer.js | 2 +-
package.json | 8 ++---
yarn.lock | 56 +++++++++++++++++++++++++-----
3 files changed, 52 insertions(+), 14 deletions(-)
diff --git a/lib/reducers/create-otp-reducer.js b/lib/reducers/create-otp-reducer.js
index bc866f3ea..14c002f36 100644
--- a/lib/reducers/create-otp-reducer.js
+++ b/lib/reducers/create-otp-reducer.js
@@ -131,7 +131,7 @@ export function getInitialState(userDefinedConfig) {
config.api.path = `/otp/routers/${routerId}`
}
- let initialModeSettings = defaultModeSettings
+ let initialModeSettings = defaultModeSettings || []
if (!initialModeSettings.length) {
initialModeSettings = []
}
diff --git a/package.json b/package.json
index 83d45ab65..c8ea4eaea 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,7 @@
"@bugsnag/plugin-react": "^7.17.0",
"@floating-ui/react": "^0.19.2",
"@opentripplanner/base-map": "^3.0.13",
- "@opentripplanner/core-utils": "^9.0.3",
+ "@opentripplanner/core-utils": "^11.0.0",
"@opentripplanner/endpoints-overlay": "^2.0.7",
"@opentripplanner/from-to-location-picker": "^2.1.7",
"@opentripplanner/geocoder": "^1.4.2",
@@ -58,7 +58,7 @@
"@opentripplanner/transit-vehicle-overlay": "^4.0.4",
"@opentripplanner/transitive-overlay": "^3.0.13",
"@opentripplanner/trip-details": "^5.0.2",
- "@opentripplanner/trip-form": "^3.1.1",
+ "@opentripplanner/trip-form": "^3.3.1",
"@opentripplanner/trip-viewer-overlay": "^2.0.5",
"@opentripplanner/vehicle-rental-overlay": "^2.1.1",
"@styled-icons/fa-regular": "^10.34.0",
@@ -132,7 +132,7 @@
"@craco/craco": "^6.3.0",
"@jackwilsdon/craco-use-babelrc": "^1.0.0",
"@opentripplanner/scripts": "^1.2.0",
- "@opentripplanner/types": "^6.0.0",
+ "@opentripplanner/types": "^6.1.0",
"@percy/cli": "^1.20.3",
"@percy/puppeteer": "^2.0.2",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.1",
@@ -240,4 +240,4 @@
"percy-css": ".percy-hide { opacity: 0!important; } "
}
}
-}
+}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 0835fc215..724a0c63f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2394,6 +2394,44 @@
maplibre-gl "^2.1.9"
react-map-gl "^7.0.15"
+"@opentripplanner/core-utils@^10.0.0":
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-10.0.0.tgz#ab5cba39097e2b15e634b1e70141076f3a5614d3"
+ integrity sha512-3T+P9GlBmeL8AHATUXbOouDtr3eYNv6VYMbVagFV9MBhYf3wSCJ3kAdBEWK+TQGfiWRfcxVJueuy8kvmVrkJtA==
+ dependencies:
+ "@conveyal/lonlat" "^1.4.1"
+ "@mapbox/polyline" "^1.1.0"
+ "@opentripplanner/geocoder" "^1.4.1"
+ "@styled-icons/foundation" "^10.34.0"
+ "@turf/along" "^6.0.1"
+ bowser "^2.7.0"
+ chroma-js "^2.4.2"
+ date-fns "^2.28.0"
+ date-fns-tz "^1.2.2"
+ graphql "^16.6.0"
+ lodash.clonedeep "^4.5.0"
+ lodash.isequal "^4.5.0"
+ qs "^6.9.1"
+
+"@opentripplanner/core-utils@^11.0.0":
+ version "11.0.0"
+ resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-11.0.0.tgz#dd40b7cd68d7d7bf4f56d87bf708d6bd4b7660ed"
+ integrity sha512-b+oPQWKpzXHeq9QdU0JmsplZX2QIRj4ARdIPJ++f5i/hpIxMnbKApwDHVkRdHz6kYCOQI7pcVNTunT7AGNvudg==
+ dependencies:
+ "@conveyal/lonlat" "^1.4.1"
+ "@mapbox/polyline" "^1.1.0"
+ "@opentripplanner/geocoder" "^1.4.1"
+ "@styled-icons/foundation" "^10.34.0"
+ "@turf/along" "^6.0.1"
+ bowser "^2.7.0"
+ chroma-js "^2.4.2"
+ date-fns "^2.28.0"
+ date-fns-tz "^1.2.2"
+ graphql "^16.6.0"
+ lodash.clonedeep "^4.5.0"
+ lodash.isequal "^4.5.0"
+ qs "^6.9.1"
+
"@opentripplanner/core-utils@^8.1.1", "@opentripplanner/core-utils@^8.2.1":
version "8.3.2"
resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-8.3.2.tgz#5095dd3ae8493e478b3f599353c6804b35f1e1dd"
@@ -2694,13 +2732,13 @@
flat "^5.0.2"
react-animate-height "^3.0.4"
-"@opentripplanner/trip-form@^3.1.1":
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/@opentripplanner/trip-form/-/trip-form-3.1.1.tgz#67d01f1fcfd31ccc758907b4324e453f2984f8b2"
- integrity sha512-A5OFHZyLW4CZDndrdjLy3ZHSQGWgaido/yN/jZXKcBHRDZK91Izd0xNAn4p4EvwpULPocg1mak/2dYwl07TWUQ==
+"@opentripplanner/trip-form@^3.3.1":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/@opentripplanner/trip-form/-/trip-form-3.3.1.tgz#3cf3212d1948ff28440600a6951847bf7a77467a"
+ integrity sha512-XDioTMNXSugz1iPWRVeP91xqJYbEOI/ZdEL9fHXllIT5c8dkg35mjCNtGtOJzaZZVtY+p3KxzD4lEWLVdAD45w==
dependencies:
"@floating-ui/react" "^0.19.2"
- "@opentripplanner/core-utils" "^8.2.1"
+ "@opentripplanner/core-utils" "^10.0.0"
"@styled-icons/bootstrap" "^10.34.0"
"@styled-icons/boxicons-regular" "^10.38.0"
"@styled-icons/fa-regular" "^10.37.0"
@@ -2719,10 +2757,10 @@
"@opentripplanner/base-map" "^3.0.11"
"@opentripplanner/core-utils" "^8.2.1"
-"@opentripplanner/types@^6.0.0":
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/@opentripplanner/types/-/types-6.0.0.tgz#3dabebd404c88030f4191f08c7692d72ca2e3c8d"
- integrity sha512-mwwj2WzkdCoG2KUYaR/4I2JkcuXr1fFUJpP4nk10YbRgzyGtGLaGIdiTXNYpwgk/5//pMHQ5Qa6psWrHpqRm1A==
+"@opentripplanner/types@^6.1.0":
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/@opentripplanner/types/-/types-6.1.0.tgz#dd5b88cc0b73939cd1eb5bd44d4768e21bedaacc"
+ integrity sha512-fFuNMJLrSCIoIWJ7VugM1Jb7HfIcRDzb8o2LNsASExWAEYDuONFxyGYT/98g82/70Grl8kCSMSAFi0lEiQ/cPQ==
"@opentripplanner/vehicle-rental-overlay@^2.1.1":
version "2.1.1"
From 91055c878240cf7c722e8cd97e72bc4fcdfdace6 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 29 Aug 2023 09:51:28 -0400
Subject: [PATCH 35/49] refactor(metro-itinerary): Update interpretation of
active.
---
lib/components/narrative/metro/metro-itinerary.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/components/narrative/metro/metro-itinerary.tsx b/lib/components/narrative/metro/metro-itinerary.tsx
index 4e65c966d..cbd0f7194 100644
--- a/lib/components/narrative/metro/metro-itinerary.tsx
+++ b/lib/components/narrative/metro/metro-itinerary.tsx
@@ -204,7 +204,7 @@ class MetroItinerary extends NarrativeItinerary {
_onMouseEnter = () => {
const { active, index, setVisibleItinerary, visible } = this.props
// Set this itinerary as visible if not already visible.
- const isVisible = visible || active === index
+ const isVisible = visible || active
if (typeof setVisibleItinerary === 'function' && !isVisible) {
setVisibleItinerary({ index })
}
From 2dacb7b4b383882083032b056b70dae9c03a517e Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 29 Aug 2023 16:11:57 -0400
Subject: [PATCH 36/49] fix(actions/location): Display alert if location was
denied.
Also, don't fetch location on loading the desktop view.
---
i18n/en-US.yml | 5 +++++
lib/actions/location.tsx | 10 ++++++++++
lib/components/app/responsive-webapp.js | 6 ++----
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/i18n/en-US.yml b/i18n/en-US.yml
index 613156575..e518a7672 100644
--- a/i18n/en-US.yml
+++ b/i18n/en-US.yml
@@ -34,6 +34,11 @@ actions:
setPaymentError: "Error setting payment info:"
setRequestStatusError: "Error setting request status:"
location:
+ deniedAccessAlert: >
+ Access to your location is blocked.
+
+ To use your current location, enable location permissions from your
+ browser, and reload the page.
geolocationNotSupportedError: Geolocation not supported by your browser
unknownPositionError: Unknown error getting position
map:
diff --git a/lib/actions/location.tsx b/lib/actions/location.tsx
index a336efb18..64e9e8921 100644
--- a/lib/actions/location.tsx
+++ b/lib/actions/location.tsx
@@ -2,6 +2,7 @@
import { createAction } from 'redux-actions'
import { Dispatch } from 'redux'
import { IntlShape } from 'react-intl'
+import { isMobile } from '@opentripplanner/core-utils/lib/ui'
import { setLocationToCurrent } from './map'
@@ -47,6 +48,15 @@ export function getCurrentPosition(
// On error
(error) => {
console.log('error getting current position', error)
+ // On desktop, after user clicks "Use location" from the location fields,
+ // show an alert and explain if location is blocked.
+ if (!isMobile() && error.code === 1) {
+ window.alert(
+ intl.formatMessage({
+ id: 'actions.location.deniedAccessAlert'
+ })
+ )
+ }
// FIXME, analyze error code to produce better error message.
// See https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPositionError
dispatch(receivedPositionError({ error }))
diff --git a/lib/components/app/responsive-webapp.js b/lib/components/app/responsive-webapp.js
index e135c16b1..0ae74b8a7 100644
--- a/lib/components/app/responsive-webapp.js
+++ b/lib/components/app/responsive-webapp.js
@@ -153,11 +153,9 @@ class ResponsiveWebapp extends Component {
}
}
- // Test location availability on load,
- // so it is reported correctly by the location fields.
- getCurrentPosition(intl)
-
if (isMobile()) {
+ // Test location availability on load
+ getCurrentPosition(intl)
// Also, watch for changes in position on mobile
navigator.geolocation.watchPosition(
// On success
From 11e8a613640ee0b0a343fe2617832b4e466e9c44 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 29 Aug 2023 16:54:36 -0400
Subject: [PATCH 37/49] improvement(actions/location): Add i18n to user-denied
error messages.
---
i18n/en-US.yml | 1 +
lib/actions/location.tsx | 16 +++++++++++++---
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/i18n/en-US.yml b/i18n/en-US.yml
index e518a7672..8c438529b 100644
--- a/i18n/en-US.yml
+++ b/i18n/en-US.yml
@@ -41,6 +41,7 @@ actions:
browser, and reload the page.
geolocationNotSupportedError: Geolocation not supported by your browser
unknownPositionError: Unknown error getting position
+ userDeniedPermission: User denied permission
map:
currentLocation: (Current Location)
user:
diff --git a/lib/actions/location.tsx b/lib/actions/location.tsx
index 64e9e8921..40ffeaa93 100644
--- a/lib/actions/location.tsx
+++ b/lib/actions/location.tsx
@@ -57,9 +57,19 @@ export function getCurrentPosition(
})
)
}
- // FIXME, analyze error code to produce better error message.
- // See https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPositionError
- dispatch(receivedPositionError({ error }))
+ const newError = { ...error }
+ if (error.code === 1) {
+ // i18n for user-denied location message (error.code = 1 on secure origins).
+ if (
+ window.location.protocol === 'https:' ||
+ window.location.host.startsWith('localhost:')
+ ) {
+ newError.message = intl.formatMessage({
+ id: 'actions.location.userDeniedPermission'
+ })
+ }
+ }
+ dispatch(receivedPositionError({ error: newError }))
},
// Options
{ enableHighAccuracy: true }
From 1b84270e8789820a5ded4a077a568b7304dc690e Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 29 Aug 2023 17:03:38 -0400
Subject: [PATCH 38/49] chore(i18n): Add missing French.
---
i18n/fr.yml | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/i18n/fr.yml b/i18n/fr.yml
index 742db4275..5c41e72fc 100644
--- a/i18n/fr.yml
+++ b/i18n/fr.yml
@@ -38,8 +38,14 @@ actions:
setPaymentError: "Erreur sur les coordonnées de paiement :"
setRequestStatusError: "Erreur sur l'état de la requête :"
location:
+ deniedAccessAlert: >
+ L'accès à votre position est refusé.
+
+ Pour utiliser votre emplacement actuel, permettez-en l'accès depuis votre
+ navigateur, et ouvrez de nouveau cette page.
geolocationNotSupportedError: La géolocalisation n'est pas prise en charge par votre navigateur.
unknownPositionError: Erreur inconnue lors de la détection de votre emplacement.
+ userDeniedPermission: Refusé par l'utilisateur
map:
currentLocation: (Emplacement actuel)
user:
@@ -178,7 +184,7 @@ components:
AdvancedOptions:
bannedRoutes: Choisissez les lignes à éviter…
bikeTolerance: Tolérance au vélo
- preferredRoutes: Choisissez les lignes preferées
+ preferredRoutes: Choisissez les lignes préferées
walkTolerance: Tolérance à la marche
AfterSignInScreen:
mainTitle: Redirection...
From 933d34a0c8fc1838653a27433651b5e21b92c218 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 30 Aug 2023 10:37:38 -0400
Subject: [PATCH 39/49] refactor(actions/location): Apply PR review feedback.
---
lib/actions/location.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/actions/location.tsx b/lib/actions/location.tsx
index 40ffeaa93..c62e9b740 100644
--- a/lib/actions/location.tsx
+++ b/lib/actions/location.tsx
@@ -50,6 +50,7 @@ export function getCurrentPosition(
console.log('error getting current position', error)
// On desktop, after user clicks "Use location" from the location fields,
// show an alert and explain if location is blocked.
+ // TODO: Consider moving the handling of unavailable location to the location-field component.
if (!isMobile() && error.code === 1) {
window.alert(
intl.formatMessage({
From 381f9edbc4184644da2b5b91fa4725d12d8d7fcf Mon Sep 17 00:00:00 2001
From: miles-grant-ibigroup
Date: Wed, 30 Aug 2023 12:36:02 -0400
Subject: [PATCH 40/49] refactor: address pr feedback
---
lib/components/user/sequential-pane-display.tsx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/components/user/sequential-pane-display.tsx b/lib/components/user/sequential-pane-display.tsx
index adf171e21..e41a953b7 100644
--- a/lib/components/user/sequential-pane-display.tsx
+++ b/lib/components/user/sequential-pane-display.tsx
@@ -52,7 +52,7 @@ class SequentialPaneDisplay extends Component> {
h1Ref = React.createRef()
- _handleFocus = () => {
+ _focusHeader = () => {
this.h1Ref?.current?.focus()
}
@@ -76,7 +76,7 @@ class SequentialPaneDisplay extends Component> {
this._routeTo(nextId)
}
}
- this._handleFocus()
+ this._focusHeader()
}
_handleToPrevPane = () => {
@@ -85,11 +85,11 @@ class SequentialPaneDisplay extends Component> {
const prevId = panes[activePaneIndex - 1].id
prevId && this._routeTo(prevId)
}
- this._handleFocus()
+ this._focusHeader()
}
componentDidMount(): void {
- this._handleFocus()
+ this._focusHeader()
}
render() {
From 1870e93eb30445fae0ba97d994b73701437763d8 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 22 Aug 2023 14:56:33 -0400
Subject: [PATCH 41/49] fix(create-otp-reducer): Ensure that responses for mode
combos are stored in same order as the combo
---
lib/actions/apiV2.js | 3 ++-
lib/components/narrative/narrative-itineraries.js | 2 +-
lib/reducers/create-otp-reducer.js | 9 ++++++++-
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/lib/actions/apiV2.js b/lib/actions/apiV2.js
index 3b9eba694..839eb7fea 100644
--- a/lib/actions/apiV2.js
+++ b/lib/actions/apiV2.js
@@ -919,7 +919,7 @@ export function routingQuery(searchId = null, updateSearchInReducer) {
dispatch(setItineraryView(ItineraryView.LIST))
- combinations.forEach((combo) => {
+ combinations.forEach((combo, index) => {
const query = generateOtp2Query(combo)
dispatch(
createGraphQLQueryAction(
@@ -982,6 +982,7 @@ export function routingQuery(searchId = null, updateSearchInReducer) {
}
return {
+ index,
response: {
plan: {
...response.data?.plan,
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index 23d1d96fe..4fa470537 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -560,7 +560,7 @@ class NarrativeItineraries extends Component {
}
const reduceErrorsFromResponse = (acc, cur) => {
- const { routingErrors } = cur?.plan
+ const { routingErrors } = cur?.plan || {}
if (routingErrors) {
routingErrors.forEach((routingError) => {
const { code, inputField } = routingError
diff --git a/lib/reducers/create-otp-reducer.js b/lib/reducers/create-otp-reducer.js
index 172ccb710..b5534a071 100644
--- a/lib/reducers/create-otp-reducer.js
+++ b/lib/reducers/create-otp-reducer.js
@@ -325,7 +325,14 @@ function createOtpReducer(config) {
searches: {
[searchId]: {
pending: { $set: activeSearch?.pending - 1 },
- response: { $push: [response] }
+ response:
+ action.payload.index !== undefined
+ ? {
+ [action.payload.index]: {
+ $set: response
+ }
+ }
+ : { $push: [response] }
}
},
ui: {
From 6954113e49e8541bdf35af84cd6c24b4a0d48f68 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 31 Aug 2023 12:03:14 -0400
Subject: [PATCH 42/49] refactor(notification-prefs-pane): Add config setting
for showing push notification settings.
---
example-config.yml | 1 +
.../user/notification-prefs-pane.tsx | 20 ++++++++++++++++---
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/example-config.yml b/example-config.yml
index b725f59a4..63fbf78cc 100644
--- a/example-config.yml
+++ b/example-config.yml
@@ -68,6 +68,7 @@ persistence:
# otp_middleware:
# apiBaseUrl: https://otp-middleware.example.com
# apiKey: your-middleware-api-key
+# supportsPushNotifications: true # If not set, push notification settings will not be shown.
### Adding additional menu items to the main menu items. Use the separator flag
### to include a separator line if you have groups of menu items
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index 3636dedec..85668867c 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -1,6 +1,7 @@
+import { connect } from 'react-redux'
import { Field, FormikProps } from 'formik'
import { FormattedMessage } from 'react-intl'
-import React, { Fragment } from 'react'
+import React from 'react'
import styled from 'styled-components'
import { GRAY_ON_WHITE } from '../util/colors'
@@ -13,6 +14,7 @@ import PhoneNumberEditor, {
} from './phone-number-editor'
interface Props extends FormikProps {
+ allowedNotificationChannels: string[]
loggedInUser: User
onRequestPhoneVerificationCode: PhoneCodeRequestHandler
onSendPhoneVerificationCode: PhoneVerificationSubmitHandler
@@ -21,7 +23,8 @@ interface Props extends FormikProps {
}
}
-const allowedNotificationChannels = ['email', 'sms', 'push']
+const allNotificationChannels = ['email', 'sms', 'push']
+const emailAndSms = ['email', 'sms']
// Styles
const NotificationOption = styled.div`
@@ -52,6 +55,7 @@ const NotificationOption = styled.div`
* User notification preferences pane.
*/
const NotificationPrefsPane = ({
+ allowedNotificationChannels,
onRequestPhoneVerificationCode,
onSendPhoneVerificationCode,
phoneFormatOptions,
@@ -115,4 +119,14 @@ const NotificationPrefsPane = ({
)
}
-export default NotificationPrefsPane
+const mapStateToProps = (state: any) => {
+ const { supportsPushNotifications } =
+ state.otp.config.persistence?.otp_middleware || {}
+ return {
+ allowedNotificationChannels: supportsPushNotifications
+ ? allNotificationChannels
+ : emailAndSms
+ }
+}
+
+export default connect(mapStateToProps)(NotificationPrefsPane)
From 97dca1d73ef0f31656d83ba1b2914aa0b424dafb Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 31 Aug 2023 12:17:01 -0400
Subject: [PATCH 43/49] refactor(notification-prefs-pane): Reduce phone options
prop drilling.
---
lib/components/user/notification-prefs-pane.tsx | 3 ++-
lib/components/user/user-account-screen.js | 7 ++-----
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index 85668867c..ffe092eb3 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -125,7 +125,8 @@ const mapStateToProps = (state: any) => {
return {
allowedNotificationChannels: supportsPushNotifications
? allNotificationChannels
- : emailAndSms
+ : emailAndSms,
+ phoneFormatOptions: state.otp.config.phoneFormatOptions
}
}
diff --git a/lib/components/user/user-account-screen.js b/lib/components/user/user-account-screen.js
index 6b05245be..78e756d01 100644
--- a/lib/components/user/user-account-screen.js
+++ b/lib/components/user/user-account-screen.js
@@ -110,8 +110,7 @@ class UserAccountScreen extends Component {
}
render() {
- const { auth0, isCreating, itemId, loggedInUser, phoneFormatOptions } =
- this.props
+ const { auth0, isCreating, itemId, loggedInUser } = this.props
const DisplayComponent = isCreating
? NewAccountWizard
: ExistingAccountDisplay
@@ -153,7 +152,6 @@ class UserAccountScreen extends Component {
onSendPhoneVerificationCode={
this._handleSendPhoneVerificationCode
}
- phoneFormatOptions={phoneFormatOptions}
/>
)
@@ -173,8 +171,7 @@ const mapStateToProps = (state, ownProps) => {
return {
isCreating,
itemId: step,
- loggedInUser: state.user.loggedInUser,
- phoneFormatOptions: state.otp.config.phoneFormatOptions
+ loggedInUser: state.user.loggedInUser
}
}
From 344442f42157939bef5dd4fc69bfcbdb6fe36ff2 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 31 Aug 2023 12:41:04 -0400
Subject: [PATCH 44/49] improvement(notification-prefs-pane): Improve checkbox
layout
---
.../user/notification-prefs-pane.tsx | 98 ++++++++++---------
lib/components/user/phone-number-editor.tsx | 2 +-
2 files changed, 51 insertions(+), 49 deletions(-)
diff --git a/lib/components/user/notification-prefs-pane.tsx b/lib/components/user/notification-prefs-pane.tsx
index ffe092eb3..127fcb10c 100644
--- a/lib/components/user/notification-prefs-pane.tsx
+++ b/lib/components/user/notification-prefs-pane.tsx
@@ -1,6 +1,7 @@
import { connect } from 'react-redux'
import { Field, FormikProps } from 'formik'
import { FormattedMessage } from 'react-intl'
+import { ListGroup, ListGroupItem } from 'react-bootstrap'
import React from 'react'
import styled from 'styled-components'
@@ -27,10 +28,9 @@ const allNotificationChannels = ['email', 'sms', 'push']
const emailAndSms = ['email', 'sms']
// Styles
-const NotificationOption = styled.div`
+const NotificationOption = styled(ListGroupItem)`
align-items: flex-start;
display: flex;
- margin-bottom: 10px;
/* Match bootstrap's spacing between checkbox and label */
& > span:first-child {
@@ -68,53 +68,55 @@ const NotificationPrefsPane = ({
- {allowedNotificationChannels.map((type) => {
- // TODO: If removing the Save/Cancel buttons on the account screen,
- // persist changes immediately when onChange is triggered.
- const inputId = `notification-channel-${type}`
- const inputDescriptionId = `${inputId}-description`
- return (
-
-
-
-
-
-
-
-
- {type === 'email' ? (
- {email}
- ) : type === 'sms' ? (
-
+ {allowedNotificationChannels.map((type) => {
+ // TODO: If removing the Save/Cancel buttons on the account screen,
+ // persist changes immediately when onChange is triggered.
+ const inputId = `notification-channel-${type}`
+ const inputDescriptionId = `${inputId}-description`
+ return (
+
+
+
- ) : (
-
- {pushDevices ? (
- // TODO: i18n
- `${pushDevices} devices registered`
- ) : (
-
- )}
-
- )}
-
-
- )
- })}
+
+
+
+
+
+ {type === 'email' ? (
+ {email}
+ ) : type === 'sms' ? (
+
+ ) : (
+
+ {pushDevices ? (
+ // TODO: i18n
+ `${pushDevices} devices registered`
+ ) : (
+
+ )}
+
+ )}
+
+
+ )
+ })}
+
)
}
diff --git a/lib/components/user/phone-number-editor.tsx b/lib/components/user/phone-number-editor.tsx
index b53d142de..b3dc52efc 100644
--- a/lib/components/user/phone-number-editor.tsx
+++ b/lib/components/user/phone-number-editor.tsx
@@ -265,7 +265,7 @@ class PhoneNumberEditor extends Component {
)}
-
+
{ariaAlertContent}
From e7b2aeebd7a27edab7c6a4595ebc15a8d5f88bab Mon Sep 17 00:00:00 2001
From: Daniel Heppner
Date: Fri, 1 Sep 2023 01:01:16 +0200
Subject: [PATCH 45/49] improvement(apiv2): use the OTP-UI conversion utility
for legacy format
---
lib/actions/apiV2.js | 49 ++++++--------------------------------------
1 file changed, 6 insertions(+), 43 deletions(-)
diff --git a/lib/actions/apiV2.js b/lib/actions/apiV2.js
index 3b9eba694..ec8aec770 100644
--- a/lib/actions/apiV2.js
+++ b/lib/actions/apiV2.js
@@ -44,7 +44,11 @@ import { rememberPlace } from './user'
import { setItineraryView } from './ui'
import { zoomToPlace } from './map'
-const { generateCombinations, generateOtp2Query } = coreUtils.queryGen
+const {
+ convertGraphQLResponseToLegacy,
+ generateCombinations,
+ generateOtp2Query
+} = coreUtils.queryGen
const { getTripOptionsFromQuery, getUrlParams } = coreUtils.query
const { randId } = coreUtils.storage
@@ -782,47 +786,6 @@ const pickupDropoffTypeToOtp1 = (otp2Type) => {
}
}
-/**
- * Converts a leg from GraphQL format to legacy REST format.
- * @param leg OTP2 GraphQL style leg
- * @returns REST shaped leg
- */
-const processLeg = (leg) => ({
- ...leg,
- agencyBrandingUrl: leg.agency?.url,
- agencyName: leg.agency?.name,
- agencyUrl: leg.agency?.url,
- alerts: aggregateAlerts(
- leg.agency?.alerts,
- leg.route?.alerts,
- leg.to?.stop?.alerts,
- leg.from?.stop?.alerts
- ),
- alightRule: pickupDropoffTypeToOtp1(leg.dropoffType),
- boardRule: pickupDropoffTypeToOtp1(leg.pickupType),
- dropOffBookingInfo: {
- latestBookingTime: leg.dropOffBookingInfo
- },
- from: {
- ...leg.from,
- stopCode: leg.from.stop?.code,
- stopId: leg.from.stop?.gtfsId
- },
- route: leg.route?.shortName,
- routeColor: leg.route?.color,
- routeId: leg.route?.id,
- routeLongName: leg.route?.longName,
- routeShortName: leg.route?.shortName,
- routeTextColor: leg.route?.textColor,
- to: {
- ...leg.to,
- stopCode: leg.to.stop?.code,
- stopId: leg.to.stop?.gtfsId
- },
- tripHeadsign: leg.trip?.tripHeadsign,
- tripId: leg.trip?.gtfsId
-})
-
const queryParamConfig = { modeButtons: DelimitedArrayParam }
export function routingQuery(searchId = null, updateSearchInReducer) {
@@ -962,7 +925,7 @@ export function routingQuery(searchId = null, updateSearchInReducer) {
const withCollapsedShortNames =
response.data?.plan?.itineraries?.map((itin) => ({
...itin,
- legs: itin.legs?.map(processLeg)
+ legs: itin.legs?.map(convertGraphQLResponseToLegacy)
}))
/* It is possible for a NO_TRANSIT_CONNECTION error to be
From bc341dea9436c2d3353de4bf023242542ce7d205 Mon Sep 17 00:00:00 2001
From: Daniel Heppner
Date: Fri, 1 Sep 2023 12:46:26 +0200
Subject: [PATCH 46/49] fix incorrect import
---
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 ec8aec770..70f116d2a 100644
--- a/lib/actions/apiV2.js
+++ b/lib/actions/apiV2.js
@@ -44,12 +44,9 @@ import { rememberPlace } from './user'
import { setItineraryView } from './ui'
import { zoomToPlace } from './map'
-const {
- convertGraphQLResponseToLegacy,
- generateCombinations,
- generateOtp2Query
-} = coreUtils.queryGen
+const { generateCombinations, generateOtp2Query } = coreUtils.queryGen
const { getTripOptionsFromQuery, getUrlParams } = coreUtils.query
+const { convertGraphQLResponseToLegacy } = coreUtils.itinerary
const { randId } = coreUtils.storage
const LIGHT_GRAY = '666666'
From 92ac6c941b335b824d90257f6222cffcfa2b09d2 Mon Sep 17 00:00:00 2001
From: Daniel Heppner
Date: Sat, 2 Sep 2023 00:52:22 +0200
Subject: [PATCH 47/49] deps: update core-utils
---
package.json | 2 +-
yarn.lock | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package.json b/package.json
index 770861132..5982b1c6f 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,7 @@
"@bugsnag/plugin-react": "^7.17.0",
"@floating-ui/react": "^0.19.2",
"@opentripplanner/base-map": "^3.0.14",
- "@opentripplanner/core-utils": "^11.0.0",
+ "@opentripplanner/core-utils": "^11.0.2",
"@opentripplanner/endpoints-overlay": "^2.0.8",
"@opentripplanner/from-to-location-picker": "^2.1.8",
"@opentripplanner/geocoder": "^1.4.2",
diff --git a/yarn.lock b/yarn.lock
index 2d9cec407..d24a5c104 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2439,10 +2439,10 @@
lodash.isequal "^4.5.0"
qs "^6.9.1"
-"@opentripplanner/core-utils@^11.0.0":
- version "11.0.0"
- resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-11.0.0.tgz#dd40b7cd68d7d7bf4f56d87bf708d6bd4b7660ed"
- integrity sha512-b+oPQWKpzXHeq9QdU0JmsplZX2QIRj4ARdIPJ++f5i/hpIxMnbKApwDHVkRdHz6kYCOQI7pcVNTunT7AGNvudg==
+"@opentripplanner/core-utils@^11.0.2":
+ version "11.0.2"
+ resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-11.0.2.tgz#ebfa939c3b7b266e3bf47dcaddda88e093430a9d"
+ integrity sha512-3oQYvnhFHY88K61j2tUkU2fm8tDci5qaMVGEgqTzxpE5NmBTUdAWU1V7W9snJoRATzz3zy+K9qrtIhGjwbwlnA==
dependencies:
"@conveyal/lonlat" "^1.4.1"
"@mapbox/polyline" "^1.1.0"
From 31c000b6b2ff458f9985ef882f41520e45752c99 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 5 Sep 2023 17:52:47 -0400
Subject: [PATCH 48/49] fix(otp reducer): Handle new FT search and updating FT
responses.
---
lib/reducers/create-otp-reducer.js | 37 +++++++++++++++++++++++++-----
1 file changed, 31 insertions(+), 6 deletions(-)
diff --git a/lib/reducers/create-otp-reducer.js b/lib/reducers/create-otp-reducer.js
index b5534a071..91ee98d72 100644
--- a/lib/reducers/create-otp-reducer.js
+++ b/lib/reducers/create-otp-reducer.js
@@ -353,30 +353,55 @@ function createOtpReducer(config) {
}
})
case 'SET_PENDING_REQUESTS':
+ if (state.searches[searchId]) {
+ return update(state, {
+ searches: {
+ [searchId]: {
+ pending: { $set: action.payload?.pending }
+ }
+ }
+ })
+ }
return update(state, {
searches: {
[searchId]: {
- pending: { $set: action.payload?.pending }
+ $set: {
+ pending: action.payload?.pending
+ }
}
}
})
case 'SET_ACTIVE_ITINERARIES':
const responseUpdate = {}
+ const responseSet = []
Object.entries(action.payload.assignedItinerariesByResponse).forEach(
([responseIdx, responsePlanItineraries]) => {
- responseUpdate[responseIdx] = {
+ const responsePart = {
plan: {
- itineraries: {
- $set: responsePlanItineraries
- }
+ itineraries: responsePlanItineraries
}
}
+ responseUpdate[responseIdx] = {
+ $set: responsePart
+ }
+ responseSet[responseIdx] = responsePart
}
)
+ if (state.searches[searchId]?.response) {
+ return update(state, {
+ searches: {
+ [searchId]: {
+ response: responseUpdate
+ }
+ }
+ })
+ }
return update(state, {
searches: {
[searchId]: {
- response: responseUpdate
+ $set: {
+ response: responseSet
+ }
}
}
})
From a7e82dc780c38bf302439457ee3f716b0edd6db9 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 6 Sep 2023 19:22:00 -0400
Subject: [PATCH 49/49] fix(otp reducer): Update successive responses, fix ft
wait for current search.
---
lib/actions/field-trip.js | 23 ++++++----
lib/reducers/create-otp-reducer.js | 68 +++++++++++++++---------------
2 files changed, 47 insertions(+), 44 deletions(-)
diff --git a/lib/actions/field-trip.js b/lib/actions/field-trip.js
index ee77d2ca1..da34ec27b 100644
--- a/lib/actions/field-trip.js
+++ b/lib/actions/field-trip.js
@@ -687,7 +687,7 @@ function checkValidityAndCapacity(state, request) {
// iterate through itineraries to check validity and assign field trip
// groups
- response.plan.itineraries.forEach((itinerary) => {
+ response.plan.itineraries.forEach((itinerary, itinIdx) => {
let itineraryCapacity = Number.POSITIVE_INFINITY
// check each individual trip to see if there aren't any trips in this
@@ -744,12 +744,13 @@ function checkValidityAndCapacity(state, request) {
// A field trip response is guaranteed to have only one itinerary, so it
// ok to set the itinerary by response as an array with a single
// itinerary.
- assignedItinerariesByResponse[responseIdx] = [
- {
- ...itinerary,
- fieldTripGroupSize: Math.min(itineraryCapacity, remainingGroupSize)
- }
- ]
+ if (!assignedItinerariesByResponse[responseIdx]) {
+ assignedItinerariesByResponse[responseIdx] = {}
+ }
+ assignedItinerariesByResponse[responseIdx][itinIdx] = {
+ ...itinerary,
+ fieldTripGroupSize: Math.min(itineraryCapacity, remainingGroupSize)
+ }
remainingGroupSize -= itineraryCapacity
}
})
@@ -844,8 +845,12 @@ function makeFieldTripPlanRequests(request, outbound, intl) {
// I do not believe that it is worth the effort. I am instead in favor of
// re-building field trip from the ground up as a separate application.
setInterval(() => {
- const activeItineraries = getActiveItineraries(getState())
- if (activeItineraries.length >= numRequests) {
+ const searchResponse = getState().otp.searches[searchId]?.response
+ const activeItineraries =
+ searchResponse?.reduce((prev, resp) => {
+ return (prev += resp?.plan?.itineraries?.length || 0)
+ }, 0) || 0
+ if (activeItineraries >= numRequests) {
resolve()
}
}, 20)
diff --git a/lib/reducers/create-otp-reducer.js b/lib/reducers/create-otp-reducer.js
index 91ee98d72..0888474e9 100644
--- a/lib/reducers/create-otp-reducer.js
+++ b/lib/reducers/create-otp-reducer.js
@@ -327,12 +327,31 @@ function createOtpReducer(config) {
pending: { $set: activeSearch?.pending - 1 },
response:
action.payload.index !== undefined
- ? {
- [action.payload.index]: {
- $set: response
+ ? state.searches[searchId].response?.[action.payload.index]
+ ? {
+ // Field Trip may make multiple requests, one itinerary at a time,
+ // to divide up large groups. In that case, append the itineraries to the plan array
+ // at the indicated response index, as if multiple itineraries were returned in one request.
+ [action.payload.index]: {
+ plan: {
+ itineraries: {
+ $push: [...response.plan.itineraries]
+ }
+ }
+ }
}
+ : {
+ // Accommodate regular mode combination responses in the order they were requested
+ // to ensure that the response order remains the same if doing the same search again.
+ [action.payload.index]: {
+ $set: response
+ }
+ }
+ : {
+ // If queries were made outside of mode combinations, just add the responses
+ // in the order they are received (order may change if doing the same search again).
+ $push: [response]
}
- : { $push: [response] }
}
},
ui: {
@@ -353,55 +372,34 @@ function createOtpReducer(config) {
}
})
case 'SET_PENDING_REQUESTS':
- if (state.searches[searchId]) {
- return update(state, {
- searches: {
- [searchId]: {
- pending: { $set: action.payload?.pending }
- }
- }
- })
- }
return update(state, {
searches: {
[searchId]: {
- $set: {
- pending: action.payload?.pending
- }
+ pending: { $set: action.payload?.pending }
}
}
})
case 'SET_ACTIVE_ITINERARIES':
const responseUpdate = {}
- const responseSet = []
Object.entries(action.payload.assignedItinerariesByResponse).forEach(
([responseIdx, responsePlanItineraries]) => {
- const responsePart = {
+ responseUpdate[responseIdx] = {
plan: {
- itineraries: responsePlanItineraries
+ itineraries: Object.entries(responsePlanItineraries).reduce(
+ (prev, [itinIdx, itin]) => {
+ prev[itinIdx] = { $set: itin }
+ return prev
+ },
+ {}
+ )
}
}
- responseUpdate[responseIdx] = {
- $set: responsePart
- }
- responseSet[responseIdx] = responsePart
}
)
- if (state.searches[searchId]?.response) {
- return update(state, {
- searches: {
- [searchId]: {
- response: responseUpdate
- }
- }
- })
- }
return update(state, {
searches: {
[searchId]: {
- $set: {
- response: responseSet
- }
+ response: responseUpdate
}
}
})