From 30ab6816d5c456d929232a1c03f31de883819a90 Mon Sep 17 00:00:00 2001 From: Steffen Kleinle Date: Thu, 17 Oct 2024 13:20:41 +0200 Subject: [PATCH 01/29] 2350: Show snackbar instead of opening settings and fix setting status if disabling --- native/src/Navigator.tsx | 7 +- native/src/components/ExportEventButton.tsx | 8 +- native/src/contexts/AppContextProvider.tsx | 9 +- .../__tests__/AppContextProvider.spec.tsx | 20 ++- native/src/hooks/useCityAppContext.ts | 4 +- native/src/routes/Settings.tsx | 42 ++----- native/src/testing/TestingAppContext.tsx | 33 ++--- native/src/utils/PushNotificationsManager.ts | 37 ++++-- .../PushNotificationsManager.spec.ts | 76 ++++++++--- .../__tests__/createSettingsSections.spec.ts | 119 +++++++----------- native/src/utils/createSettingsSections.ts | 102 ++++++--------- .../2350-pn-permission-settings.yml | 7 ++ translations/translations.json | 39 +----- 13 files changed, 247 insertions(+), 256 deletions(-) create mode 100644 release-notes/unreleased/2350-pn-permission-settings.yml diff --git a/native/src/Navigator.tsx b/native/src/Navigator.tsx index b9afa30bc9..aeb056c4c6 100644 --- a/native/src/Navigator.tsx +++ b/native/src/Navigator.tsx @@ -88,7 +88,8 @@ const Stack = createStackNavigator() const Navigator = (): ReactElement | null => { const showSnackbar = useSnackbar() - const { settings, cityCode, changeCityCode, languageCode, updateSettings } = useAppContext() + const appContext = useAppContext() + const { settings, cityCode, changeCityCode, updateSettings } = appContext const navigation = useNavigation>() const [initialRoute, setInitialRoute] = useState(null) @@ -96,8 +97,8 @@ const Navigator = (): ReactElement | null => { const { data: cities, error: citiesError, refresh: refreshCities } = useLoadCities() useEffect(() => { - initialPushNotificationRequest(cityCode, languageCode).catch(reportError) - }, [cityCode, languageCode]) + initialPushNotificationRequest(appContext).catch(reportError) + }, [appContext]) useForegroundPushNotificationListener({ showSnackbar, navigate: navigation.navigate }) diff --git a/native/src/components/ExportEventButton.tsx b/native/src/components/ExportEventButton.tsx index f09e16abbf..35ea57a4d7 100644 --- a/native/src/components/ExportEventButton.tsx +++ b/native/src/components/ExportEventButton.tsx @@ -1,9 +1,9 @@ import { DateTime } from 'luxon' import React, { ReactElement, useState } from 'react' import { useTranslation } from 'react-i18next' -import { Linking, Platform } from 'react-native' +import { Platform } from 'react-native' import RNCalendarEvents, { Calendar, CalendarEventWritable, RecurrenceFrequency } from 'react-native-calendar-events' -import { PERMISSIONS, requestMultiple } from 'react-native-permissions' +import { PERMISSIONS, openSettings, requestMultiple } from 'react-native-permissions' import { Frequency } from 'rrule' import styled from 'styled-components/native' @@ -89,8 +89,8 @@ const ExportEventButton = ({ event }: ExportEventButtonType): ReactElement => { showSnackbar({ text: 'noCalendarPermission', positiveAction: { - label: t('settings'), - onPress: Linking.openSettings, + label: t('layout:settings'), + onPress: openSettings, }, }) return diff --git a/native/src/contexts/AppContextProvider.tsx b/native/src/contexts/AppContextProvider.tsx index 14f72b140e..47cdc7ebde 100644 --- a/native/src/contexts/AppContextProvider.tsx +++ b/native/src/contexts/AppContextProvider.tsx @@ -34,6 +34,7 @@ type AppContextProviderProps = { const AppContextProvider = ({ children }: AppContextProviderProps): ReactElement | null => { const [settings, setSettings] = useState(null) + const allowPushNotifications = !!settings?.allowPushNotifications const cityCode = settings?.selectedCity const languageCode = settings?.contentLanguage const { i18n } = useTranslation() @@ -55,10 +56,10 @@ const AppContextProvider = ({ children }: AppContextProviderProps): ReactElement unsubscribeNews(cityCode, languageCode).catch(reportError) } if (languageCode && newCityCode) { - subscribeNews(newCityCode, languageCode).catch(reportError) + subscribeNews({ cityCode: newCityCode, languageCode, allowPushNotifications }).catch(reportError) } }, - [updateSettings, cityCode, languageCode], + [updateSettings, cityCode, languageCode, allowPushNotifications], ) const changeLanguageCode = useCallback( @@ -68,10 +69,10 @@ const AppContextProvider = ({ children }: AppContextProviderProps): ReactElement unsubscribeNews(cityCode, languageCode).catch(reportError) } if (cityCode) { - subscribeNews(cityCode, newLanguageCode).catch(reportError) + subscribeNews({ cityCode, languageCode: newLanguageCode, allowPushNotifications }).catch(reportError) } }, - [updateSettings, cityCode, languageCode], + [updateSettings, cityCode, languageCode, allowPushNotifications], ) useEffect(() => { diff --git a/native/src/contexts/__tests__/AppContextProvider.spec.tsx b/native/src/contexts/__tests__/AppContextProvider.spec.tsx index 04e0be5ab3..4429802558 100644 --- a/native/src/contexts/__tests__/AppContextProvider.spec.tsx +++ b/native/src/contexts/__tests__/AppContextProvider.spec.tsx @@ -135,7 +135,7 @@ describe('AppContextProvider', () => { expect(await appSettings.loadSettings()).toMatchObject({ selectedCity: 'hallo' }) expect(setSettings).toHaveBeenCalledTimes(1) expect(subscribeNews).toHaveBeenCalledTimes(1) - expect(subscribeNews).toHaveBeenCalledWith('hallo', 'de') + expect(subscribeNews).toHaveBeenCalledWith({ cityCode: 'hallo', languageCode: 'de', allowPushNotifications: true }) }) it('should select city', async () => { @@ -150,7 +150,11 @@ describe('AppContextProvider', () => { expect(await appSettings.loadSettings()).toMatchObject({ selectedCity: 'augsburg' }) expect(setSettings).toHaveBeenCalledTimes(1) expect(subscribeNews).toHaveBeenCalledTimes(1) - expect(subscribeNews).toHaveBeenCalledWith('augsburg', 'de') + expect(subscribeNews).toHaveBeenCalledWith({ + cityCode: 'augsburg', + languageCode: 'de', + allowPushNotifications: true, + }) expect(unsubscribeNews).not.toHaveBeenCalled() }) @@ -166,7 +170,11 @@ describe('AppContextProvider', () => { expect(await appSettings.loadSettings()).toMatchObject({ selectedCity: 'augsburg' }) expect(setSettings).toHaveBeenCalledTimes(1) expect(subscribeNews).toHaveBeenCalledTimes(1) - expect(subscribeNews).toHaveBeenCalledWith('augsburg', 'de') + expect(subscribeNews).toHaveBeenCalledWith({ + cityCode: 'augsburg', + languageCode: 'de', + allowPushNotifications: true, + }) expect(unsubscribeNews).toHaveBeenCalledTimes(1) expect(unsubscribeNews).toHaveBeenCalledWith('muenchen', 'de') }) @@ -198,7 +206,11 @@ describe('AppContextProvider', () => { expect(await appSettings.loadSettings()).toMatchObject({ contentLanguage: 'ar' }) expect(setSettings).toHaveBeenCalledTimes(1) expect(subscribeNews).toHaveBeenCalledTimes(1) - expect(subscribeNews).toHaveBeenCalledWith('muenchen', 'ar') + expect(subscribeNews).toHaveBeenCalledWith({ + cityCode: 'muenchen', + languageCode: 'ar', + allowPushNotifications: true, + }) expect(unsubscribeNews).toHaveBeenCalledTimes(1) expect(unsubscribeNews).toHaveBeenCalledWith('muenchen', 'de') }) diff --git a/native/src/hooks/useCityAppContext.ts b/native/src/hooks/useCityAppContext.ts index c6d9fe1763..07342b9206 100644 --- a/native/src/hooks/useCityAppContext.ts +++ b/native/src/hooks/useCityAppContext.ts @@ -2,13 +2,13 @@ import { useContext } from 'react' import { AppContext, AppContextType } from '../contexts/AppContextProvider' -type UseCityAppContextReturn = AppContextType & { +export type CityAppContext = AppContextType & { cityCode: string } export const useAppContext = (): AppContextType => useContext(AppContext) -const useCityAppContext = (): UseCityAppContextReturn => { +const useCityAppContext = (): CityAppContext => { const { cityCode, ...context } = useAppContext() if (!cityCode) { throw new Error('City code not set!') diff --git a/native/src/routes/Settings.tsx b/native/src/routes/Settings.tsx index 3a806e5296..66e176e8fb 100644 --- a/native/src/routes/Settings.tsx +++ b/native/src/routes/Settings.tsx @@ -1,4 +1,4 @@ -import React, { ReactElement, useContext } from 'react' +import React, { ReactElement } from 'react' import { useTranslation } from 'react-i18next' import { SectionList, SectionListData } from 'react-native' import styled from 'styled-components/native' @@ -10,10 +10,8 @@ import Layout from '../components/Layout' import SettingItem from '../components/SettingItem' import ItemSeparator from '../components/base/ItemSeparator' import { NavigationProps } from '../constants/NavigationTypes' -import { AppContext } from '../contexts/AppContextProvider' -import { useAppContext } from '../hooks/useCityAppContext' +import useCityAppContext from '../hooks/useCityAppContext' import useSnackbar from '../hooks/useSnackbar' -import { SettingsType } from '../utils/AppSettings' import createSettingsSections, { SettingsSectionType } from '../utils/createSettingsSections' import { log, reportError } from '../utils/sentry' @@ -31,36 +29,25 @@ const SectionHeader = styled.Text` ` const Settings = ({ navigation }: SettingsProps): ReactElement => { - const { settings, updateSettings } = useAppContext() - const { cityCode, languageCode } = useContext(AppContext) + const appContext = useCityAppContext() const showSnackbar = useSnackbar() const { t } = useTranslation('settings') + const { settings } = appContext - const setSetting = async ( - changeSetting: (settings: SettingsType) => Partial, - changeAction?: (settings: SettingsType) => Promise, - ) => { + const safeOnPress = (update: () => Promise | void) => () => { const oldSettings = settings - const newSettings = { ...oldSettings, ...changeSetting(settings) } - updateSettings(newSettings) - - try { - const successful = changeAction ? await changeAction(newSettings) : true - - if (!successful) { - updateSettings(oldSettings) - } - } catch (e) { + update()?.catch(e => { log('Failed to persist settings.', 'error') reportError(e) - updateSettings(oldSettings) - } + appContext.updateSettings(oldSettings) + showSnackbar({ text: t('error:unknownError') }) + }) } const renderItem = ({ item }: { item: SettingsSectionType }) => { - const { getSettingValue, ...otherProps } = item + const { getSettingValue, onPress, ...otherProps } = item const value = !!(getSettingValue && getSettingValue(settings)) - return + return } const renderSectionHeader = ({ section: { title } }: { section: SectionType }) => { @@ -72,13 +59,10 @@ const Settings = ({ navigation }: SettingsProps): ReactElement => { } const sections = createSettingsSections({ - setSetting, - t, - languageCode, - cityCode, + appContext, navigation, - settings, showSnackbar, + t, }) return ( diff --git a/native/src/testing/TestingAppContext.tsx b/native/src/testing/TestingAppContext.tsx index 6a991ee9d7..fc1961a187 100644 --- a/native/src/testing/TestingAppContext.tsx +++ b/native/src/testing/TestingAppContext.tsx @@ -3,27 +3,30 @@ import React, { ReactElement, ReactNode } from 'react' import { AppContext, AppContextType } from '../contexts/AppContextProvider' import { defaultSettings, SettingsType } from '../utils/AppSettings' -const TestingAppContext = ({ - children, +type TestingAppContextParams = { settings?: Partial } & Omit, 'settings'> + +export const testingAppContext = ({ settings = {}, cityCode = 'augsburg', languageCode = 'de', changeCityCode = jest.fn(), changeLanguageCode = jest.fn(), updateSettings = jest.fn(), -}: { - settings?: Partial - children: ReactNode -} & Omit, 'settings'>): ReactElement => { - const context = { - settings: { ...defaultSettings, ...settings }, - cityCode, - languageCode, - updateSettings, - changeCityCode, - changeLanguageCode, - } +}: TestingAppContextParams): AppContextType => ({ + settings: { ...defaultSettings, ...settings }, + cityCode, + languageCode, + updateSettings, + changeCityCode, + changeLanguageCode, +}) + +const TestingAppContextProvider = ({ + children, + ...props +}: { children: ReactNode } & TestingAppContextParams): ReactElement => { + const context = testingAppContext(props) return {children} } -export default TestingAppContext +export default TestingAppContextProvider diff --git a/native/src/utils/PushNotificationsManager.ts b/native/src/utils/PushNotificationsManager.ts index 24ca65232e..525e60a1d6 100644 --- a/native/src/utils/PushNotificationsManager.ts +++ b/native/src/utils/PushNotificationsManager.ts @@ -9,10 +9,12 @@ import { LOCAL_NEWS_TYPE, NEWS_ROUTE, NonNullableRouteInformationType } from 'sh import { SnackbarType } from '../components/SnackbarContainer' import { RoutesType } from '../constants/NavigationTypes' import buildConfig from '../constants/buildConfig' +import { AppContextType } from '../contexts/AppContextProvider' import urlFromRouteInformation from '../navigation/url' -import appSettings from './AppSettings' import { log, reportError } from './sentry' +type UpdateSettingsType = (settings: { allowPushNotifications: boolean }) => void + type Message = FirebaseMessagingTypes.RemoteMessage & { notification: { title: string } data: { @@ -30,7 +32,7 @@ const importFirebaseMessaging = async (): Promise<() => FirebaseMessagingTypes.M export const pushNotificationsEnabled = (): boolean => buildConfig().featureFlags.pushNotifications && !buildConfig().featureFlags.floss -export const requestPushNotificationPermission = async (): Promise => { +export const requestPushNotificationPermission = async (updateSettings: UpdateSettingsType): Promise => { if (!pushNotificationsEnabled()) { log('Push notifications disabled, no permissions requested.') return false @@ -41,7 +43,7 @@ export const requestPushNotificationPermission = async (): Promise => { if (permissionStatus !== RESULTS.GRANTED) { log(`Permission denied, disabling push notifications in settings.`) - await appSettings.setSettings({ allowPushNotifications: false }) + updateSettings({ allowPushNotifications: false }) } return permissionStatus === RESULTS.GRANTED @@ -65,15 +67,27 @@ export const unsubscribeNews = async (city: string, language: string): Promise => { + +type SubscribeNewsParams = { + cityCode: string + languageCode: string + allowPushNotifications: boolean + skipSettingsCheck?: boolean +} + +export const subscribeNews = async ({ + cityCode, + languageCode, + allowPushNotifications, + skipSettingsCheck = false, +}: SubscribeNewsParams): Promise => { try { - const { allowPushNotifications } = await appSettings.loadSettings() if (!pushNotificationsEnabled() || (!allowPushNotifications && !skipSettingsCheck)) { log('Push notifications disabled, subscription skipped.') return } - const topic = newsTopic(city, language) + const topic = newsTopic(cityCode, languageCode) const messaging = await importFirebaseMessaging() await messaging().subscribeToTopic(topic) @@ -154,7 +168,6 @@ export const backgroundAppStatePushNotificationListener = (listener: (url: strin importFirebaseMessaging() .then(messaging => { const onReceiveURL = ({ url }: { url: string }) => listener(url) - const onReceiveURLListener = Linking.addListener('url', onReceiveURL) const unsubscribeNotification = messaging().onNotificationOpenedApp(message => @@ -175,13 +188,15 @@ export const backgroundAppStatePushNotificationListener = (listener: (url: strin // Since Android 13 and iOS 17 an explicit permission request is needed, otherwise push notifications are not received. // Therefore request the permissions once if not yet granted and subscribe to the current channel if successful. // See https://github.com/digitalfabrik/integreat-app/issues/2438 and https://github.com/digitalfabrik/integreat-app/issues/2655 -export const initialPushNotificationRequest = async (cityCode: string | null, languageCode: string): Promise => { - const { allowPushNotifications } = await appSettings.loadSettings() +export const initialPushNotificationRequest = async (appContext: AppContextType): Promise => { + const { cityCode, languageCode, settings, updateSettings } = appContext + const { allowPushNotifications } = settings + const pushNotificationPermissionGranted = (await checkNotifications()).status === RESULTS.GRANTED if (!pushNotificationPermissionGranted && allowPushNotifications) { - const success = await requestPushNotificationPermission() + const success = await requestPushNotificationPermission(updateSettings) if (success && cityCode) { - await subscribeNews(cityCode, languageCode) + await subscribeNews({ cityCode, languageCode, allowPushNotifications }) } } } diff --git a/native/src/utils/__tests__/PushNotificationsManager.spec.ts b/native/src/utils/__tests__/PushNotificationsManager.spec.ts index f31691f04a..985219527a 100644 --- a/native/src/utils/__tests__/PushNotificationsManager.spec.ts +++ b/native/src/utils/__tests__/PushNotificationsManager.spec.ts @@ -1,23 +1,20 @@ -import AsyncStorage from '@react-native-async-storage/async-storage' import messaging, { FirebaseMessagingTypes } from '@react-native-firebase/messaging' import { mocked } from 'jest-mock' import { requestNotifications } from 'react-native-permissions' import buildConfig from '../../constants/buildConfig' -import appSettings from '../AppSettings' import * as PushNotificationsManager from '../PushNotificationsManager' jest.mock('@react-native-firebase/messaging', () => jest.fn(() => ({}))) describe('PushNotificationsManager', () => { - beforeEach(() => { - AsyncStorage.clear() - jest.clearAllMocks() - }) + beforeEach(jest.clearAllMocks) + const mockedFirebaseMessaging = mocked<() => FirebaseMessagingTypes.Module>(messaging) const mockedBuildConfig = mocked(buildConfig) const previousFirebaseMessaging = mockedFirebaseMessaging() const navigateToDeepLink = jest.fn() + const updateSettings = jest.fn() const mockBuildConfig = (pushNotifications: boolean, floss: boolean) => { const previous = buildConfig() @@ -57,7 +54,7 @@ describe('PushNotificationsManager', () => { return previous }) - expect(await PushNotificationsManager.requestPushNotificationPermission()).toBeFalsy() + expect(await PushNotificationsManager.requestPushNotificationPermission(updateSettings)).toBeFalsy() expect(mockRequestPermission).not.toHaveBeenCalled() }) @@ -70,7 +67,7 @@ describe('PushNotificationsManager', () => { return previous }) - expect(await PushNotificationsManager.requestPushNotificationPermission()).toBeFalsy() + expect(await PushNotificationsManager.requestPushNotificationPermission(updateSettings)).toBeFalsy() expect(mockRequestPermission).not.toHaveBeenCalled() }) @@ -78,16 +75,17 @@ describe('PushNotificationsManager', () => { mockBuildConfig(true, false) mocked(requestNotifications).mockImplementationOnce(async () => ({ status: 'blocked', settings: {} })) - expect(await PushNotificationsManager.requestPushNotificationPermission()).toBeFalsy() - expect((await appSettings.loadSettings()).allowPushNotifications).toBe(false) + expect(await PushNotificationsManager.requestPushNotificationPermission(updateSettings)).toBeFalsy() + expect(updateSettings).toHaveBeenCalledTimes(1) + expect(updateSettings).toHaveBeenCalledWith({ allowPushNotifications: false }) }) it('should request permissions and return true if granted', async () => { mockBuildConfig(true, false) mocked(requestNotifications).mockImplementationOnce(async () => ({ status: 'granted', settings: {} })) - expect(await PushNotificationsManager.requestPushNotificationPermission()).toBeTruthy() - expect((await appSettings.loadSettings()).allowPushNotifications).toBe(true) + expect(await PushNotificationsManager.requestPushNotificationPermission(updateSettings)).toBeTruthy() + expect(updateSettings).not.toHaveBeenCalled() }) }) @@ -143,7 +141,11 @@ describe('PushNotificationsManager', () => { return previous }) - await PushNotificationsManager.subscribeNews('augsburg', 'de') + await PushNotificationsManager.subscribeNews({ + cityCode: 'augsburg', + languageCode: 'de', + allowPushNotifications: true, + }) expect(mockSubscribeToTopic).not.toHaveBeenCalled() }) @@ -156,7 +158,28 @@ describe('PushNotificationsManager', () => { return previous }) - await PushNotificationsManager.subscribeNews('augsburg', 'de') + await PushNotificationsManager.subscribeNews({ + cityCode: 'augsburg', + languageCode: 'de', + allowPushNotifications: true, + }) + expect(mockSubscribeToTopic).not.toHaveBeenCalled() + }) + + it('should return and do nothing if it is disabled in settings', async () => { + mockBuildConfig(true, false) + const mockSubscribeToTopic = jest.fn() + mockedFirebaseMessaging.mockImplementation(() => { + const previous = previousFirebaseMessaging + previous.subscribeToTopic = mockSubscribeToTopic + return previous + }) + + await PushNotificationsManager.subscribeNews({ + cityCode: 'augsburg', + languageCode: 'de', + allowPushNotifications: false, + }) expect(mockSubscribeToTopic).not.toHaveBeenCalled() }) @@ -169,7 +192,30 @@ describe('PushNotificationsManager', () => { return previous }) - await PushNotificationsManager.subscribeNews('augsburg', 'de') + await PushNotificationsManager.subscribeNews({ + cityCode: 'augsburg', + languageCode: 'de', + allowPushNotifications: true, + }) + expect(mockSubscribeToTopic).toHaveBeenCalledWith('augsburg-de-news') + expect(mockSubscribeToTopic).toHaveBeenCalledTimes(1) + }) + + it('should call subscribeToTopic even if push notifications are disabled but skipSettingsCheck is true', async () => { + mockBuildConfig(true, false) + const mockSubscribeToTopic = jest.fn() + mockedFirebaseMessaging.mockImplementation(() => { + const previous = previousFirebaseMessaging + previous.subscribeToTopic = mockSubscribeToTopic + return previous + }) + + await PushNotificationsManager.subscribeNews({ + cityCode: 'augsburg', + languageCode: 'de', + allowPushNotifications: false, + skipSettingsCheck: true, + }) expect(mockSubscribeToTopic).toHaveBeenCalledWith('augsburg-de-news') expect(mockSubscribeToTopic).toHaveBeenCalledTimes(1) }) diff --git a/native/src/utils/__tests__/createSettingsSections.spec.ts b/native/src/utils/__tests__/createSettingsSections.spec.ts index 7061ffda6c..bd6eb9f7db 100644 --- a/native/src/utils/__tests__/createSettingsSections.spec.ts +++ b/native/src/utils/__tests__/createSettingsSections.spec.ts @@ -1,11 +1,11 @@ import { TFunction } from 'i18next' import { mocked } from 'jest-mock' -import { openSettings } from 'react-native-permissions' import { SettingsRouteType } from 'shared' +import { testingAppContext } from '../../testing/TestingAppContext' import createNavigationScreenPropMock from '../../testing/createNavigationPropMock' -import { defaultSettings, SettingsType } from '../AppSettings' +import { SettingsType } from '../AppSettings' import { pushNotificationsEnabled, requestPushNotificationPermission, @@ -31,40 +31,23 @@ const mockUnsubscribeNews = mocked(unsubscribeNews) const mockSubscribeNews = mocked(subscribeNews) const mockedPushNotificationsEnabled = mocked(pushNotificationsEnabled) -type changeSettingFnType = (settings: SettingsType) => Partial -type changeActionFnType = void | ((newSettings: SettingsType) => Promise) - describe('createSettingsSections', () => { - let changeSetting: changeSettingFnType - let changeAction: void | ((newSettings: SettingsType) => Promise) - - beforeEach(() => { - jest.clearAllMocks() - changeSetting = settings => settings - changeAction = async () => true - }) - - const setSetting = async (newChangeSetting: changeSettingFnType, newChangeAction: changeActionFnType) => { - changeSetting = newChangeSetting - changeAction = newChangeAction - } + beforeEach(jest.clearAllMocks) const t = ((key: string) => key) as TFunction - const languageCode = 'de' + const updateSettings = jest.fn() const cityCode = 'augsburg' + const appContext = { ...testingAppContext({}), cityCode, updateSettings } const navigation = createNavigationScreenPropMock() const showSnackbar = jest.fn() - const createSettings = () => + const createSettings = (params: Partial = {}) => createSettingsSections({ - t, - languageCode, - cityCode, + appContext: { ...appContext, settings: { ...appContext.settings, ...params } }, navigation, - settings: defaultSettings, - setSetting, showSnackbar, + t, })[0]!.data describe('allowPushNotifications', () => { @@ -75,89 +58,83 @@ describe('createSettingsSections', () => { expect(sections.find(it => it.title === 'pushNewsTitle')).toBeFalsy() }) - it('should set correct setting on press', () => { + it('should set correct setting on press', async () => { mockedPushNotificationsEnabled.mockImplementation(() => true) const sections = createSettings() - const pushNotificationSection = sections.find(it => it.title === 'pushNewsTitle') - // Initialize changeSetting and changeAction - pushNotificationSection!.onPress() - - const settings = defaultSettings - settings.allowPushNotifications = false - const changedSettings = changeSetting(settings) - expect(pushNotificationSection!.getSettingValue!(settings)).toBeFalsy() - expect(changedSettings.allowPushNotifications).toBeTruthy() - settings.allowPushNotifications = true - const changedSettings2 = changeSetting(settings) - expect(pushNotificationSection!.getSettingValue!(settings)).toBeTruthy() - expect(changedSettings2.allowPushNotifications).toBeFalsy() + const pushNotificationSection = sections.find(it => it.title === 'pushNewsTitle')! + await pushNotificationSection!.onPress() + expect(updateSettings).toHaveBeenCalledTimes(1) + expect(updateSettings).toHaveBeenCalledWith({ allowPushNotifications: false }) + + expect( + pushNotificationSection.getSettingValue!({ ...appContext.settings, allowPushNotifications: false }), + ).toBeFalsy() + expect( + pushNotificationSection!.getSettingValue!({ ...appContext.settings, allowPushNotifications: true }), + ).toBeTruthy() }) it('should unsubscribe from push notification topic', async () => { mockedPushNotificationsEnabled.mockImplementation(() => true) const sections = createSettings() - const pushNotificationSection = sections.find(it => it.title === 'pushNewsTitle') - // Initialize changeSetting and changeAction - pushNotificationSection?.onPress() - const newSettings = defaultSettings - newSettings.allowPushNotifications = false - - const assertedChangeAction = changeAction as (newSettings: SettingsType) => Promise + const pushNotificationSection = sections.find(it => it.title === 'pushNewsTitle')! expect(mockUnsubscribeNews).not.toHaveBeenCalled() - const successful = await assertedChangeAction(newSettings) - expect(successful).toBe(true) + await pushNotificationSection.onPress() + expect(mockUnsubscribeNews).toHaveBeenCalledTimes(1) - expect(mockUnsubscribeNews).toHaveBeenCalledWith(cityCode, languageCode) + expect(mockUnsubscribeNews).toHaveBeenCalledWith(cityCode, appContext.languageCode) expect(mockSubscribeNews).not.toHaveBeenCalled() expect(mockRequestPushNotificationPermission).not.toHaveBeenCalled() + + expect(updateSettings).toHaveBeenCalledTimes(1) + expect(updateSettings).toHaveBeenCalledWith({ allowPushNotifications: false }) }) it('should subscribe to push notification topic if permission is granted', async () => { mockedPushNotificationsEnabled.mockImplementation(() => true) - const sections = createSettings() - const pushNotificationSection = sections.find(it => it.title === 'pushNewsTitle') - // Initialize changeSetting and changeAction - pushNotificationSection?.onPress() - const newSettings = defaultSettings - newSettings.allowPushNotifications = true - - const assertedChangeAction = changeAction as (newSettings: SettingsType) => Promise + const sections = createSettings({ allowPushNotifications: false }) + const pushNotificationSection = sections.find(it => it.title === 'pushNewsTitle')! expect(mockRequestPushNotificationPermission).not.toHaveBeenCalled() expect(mockSubscribeNews).not.toHaveBeenCalled() mockRequestPushNotificationPermission.mockImplementationOnce(async () => true) - const successful = await assertedChangeAction(newSettings) - expect(successful).toBe(true) + await pushNotificationSection.onPress() + expect(mockRequestPushNotificationPermission).toHaveBeenCalledTimes(1) expect(mockSubscribeNews).toHaveBeenCalledTimes(1) - expect(mockSubscribeNews).toHaveBeenCalledWith(cityCode, languageCode, true) + expect(mockSubscribeNews).toHaveBeenCalledWith({ + cityCode, + languageCode: appContext.languageCode, + allowPushNotifications: true, + skipSettingsCheck: true, + }) expect(mockUnsubscribeNews).not.toHaveBeenCalled() + + expect(updateSettings).toHaveBeenCalledTimes(1) + expect(updateSettings).toHaveBeenCalledWith({ allowPushNotifications: true }) }) it('should open settings and return false if permissions not granted', async () => { mockedPushNotificationsEnabled.mockImplementation(() => true) - const sections = createSettings() - const pushNotificationSection = sections.find(it => it.title === 'pushNewsTitle') - // Initialize changeSetting and changeAction - pushNotificationSection?.onPress() - const newSettings = defaultSettings - newSettings.allowPushNotifications = true - - const assertedChangeAction = changeAction as (newSettings: SettingsType) => Promise + const sections = createSettings({ allowPushNotifications: false }) + const pushNotificationSection = sections.find(it => it.title === 'pushNewsTitle')! expect(mockRequestPushNotificationPermission).not.toHaveBeenCalled() expect(mockSubscribeNews).not.toHaveBeenCalled() mockRequestPushNotificationPermission.mockImplementationOnce(async () => false) - const successful = await assertedChangeAction(newSettings) - expect(successful).toBe(false) + await pushNotificationSection.onPress() + expect(mockRequestPushNotificationPermission).toHaveBeenCalledTimes(1) - expect(openSettings).toHaveBeenCalledTimes(1) expect(mockSubscribeNews).not.toHaveBeenCalled() expect(mockUnsubscribeNews).not.toHaveBeenCalled() + + expect(updateSettings).toHaveBeenCalledTimes(2) + expect(updateSettings).toHaveBeenLastCalledWith({ allowPushNotifications: false }) + expect(showSnackbar).toHaveBeenCalledTimes(1) }) }) }) diff --git a/native/src/utils/createSettingsSections.ts b/native/src/utils/createSettingsSections.ts index c526f88ff4..e10a547358 100644 --- a/native/src/utils/createSettingsSections.ts +++ b/native/src/utils/createSettingsSections.ts @@ -9,6 +9,7 @@ import { SnackbarType } from '../components/SnackbarContainer' import NativeConstants from '../constants/NativeConstants' import { NavigationProps } from '../constants/NavigationTypes' import buildConfig from '../constants/buildConfig' +import { CityAppContext } from '../hooks/useCityAppContext' import { SettingsType } from './AppSettings' import { pushNotificationsEnabled, @@ -19,15 +20,10 @@ import { import openExternalUrl from './openExternalUrl' import { initSentry } from './sentry' -export type SetSettingFunctionType = ( - changeSetting: (settings: SettingsType) => Partial, - changeAction?: (newSettings: SettingsType) => Promise, -) => Promise - export type SettingsSectionType = { title: string description?: string - onPress: () => void + onPress: () => Promise | void bigTitle?: boolean role?: Role hasSwitch?: boolean @@ -42,23 +38,17 @@ const volatileValues = { const TRIGGER_VERSION_TAPS = 25 type CreateSettingsSectionsProps = { - setSetting: SetSettingFunctionType - t: TFunction - languageCode: string - cityCode: string | null | undefined + appContext: CityAppContext navigation: NavigationProps - settings: SettingsType showSnackbar: (snackbar: SnackbarType) => void + t: TFunction<'error'> } const createSettingsSections = ({ - setSetting, - t, - languageCode, - cityCode, + appContext: { settings, updateSettings, cityCode, languageCode }, navigation, - settings, showSnackbar, + t, }: CreateSettingsSectionsProps): Readonly>> => [ { title: null, @@ -71,34 +61,29 @@ const createSettingsSections = ({ description: t('pushNewsDescription'), hasSwitch: true, getSettingValue: (settings: SettingsType) => settings.allowPushNotifications, - onPress: () => { - setSetting( - settings => ({ - allowPushNotifications: !settings.allowPushNotifications, - }), - async (newSettings): Promise => { - if (!cityCode) { - // No city selected so nothing to do here (should not ever happen since settings are only available from city content routes) - return true - } + onPress: async () => { + const allowPushNotifications = !settings.allowPushNotifications + updateSettings({ allowPushNotifications }) + if (!allowPushNotifications) { + await unsubscribeNews(cityCode, languageCode) + return + } - if (newSettings.allowPushNotifications) { - const status = await requestPushNotificationPermission() + const status = await requestPushNotificationPermission(updateSettings) - if (status) { - await subscribeNews(cityCode, languageCode, true) - } else { - // If the user has rejected the permission once, it can only be changed in the system settings - openSettings() - // Not successful, reset displayed setting in app - return false - } - } else { - await unsubscribeNews(cityCode, languageCode) - } - return true - }, - ) + if (status) { + await subscribeNews({ cityCode, languageCode, allowPushNotifications, skipSettingsCheck: true }) + } else { + updateSettings({ allowPushNotifications: false }) + // If the user has rejected the permission once, it can only be changed in the system settings + showSnackbar({ + text: 'noPushNotificationPermission', + positiveAction: { + label: t('layout:settings'), + onPress: openSettings, + }, + }) + } }, }, ]), @@ -109,21 +94,16 @@ const createSettingsSections = ({ }), hasSwitch: true, getSettingValue: (settings: SettingsType) => settings.errorTracking, - onPress: () => { - setSetting( - settings => ({ - errorTracking: !settings.errorTracking, - }), - async newSettings => { - const client = Sentry.getCurrentHub().getClient() - if (newSettings.errorTracking && !client) { - initSentry() - } else if (client) { - client.getOptions().enabled = !!newSettings.errorTracking - } - return true - }, - ) + onPress: async () => { + const errorTracking = !settings.errorTracking + updateSettings({ errorTracking }) + + const client = Sentry.getClient() + if (errorTracking && !client) { + initSentry() + } else if (client) { + client.getOptions().enabled = errorTracking + } }, }, { @@ -138,19 +118,19 @@ const createSettingsSections = ({ title: t('about', { appName: buildConfig().appName, }), - onPress: () => { + onPress: async () => { const { aboutUrls } = buildConfig() const aboutUrl = aboutUrls[languageCode] || aboutUrls.default - openExternalUrl(aboutUrl, showSnackbar) + await openExternalUrl(aboutUrl, showSnackbar) }, }, { role: 'link', title: t('privacyPolicy'), - onPress: () => { + onPress: async () => { const { privacyUrls } = buildConfig() const privacyUrl = privacyUrls[languageCode] || privacyUrls.default - openExternalUrl(privacyUrl, showSnackbar) + await openExternalUrl(privacyUrl, showSnackbar) }, }, { diff --git a/release-notes/unreleased/2350-pn-permission-settings.yml b/release-notes/unreleased/2350-pn-permission-settings.yml new file mode 100644 index 0000000000..b1fabb1f09 --- /dev/null +++ b/release-notes/unreleased/2350-pn-permission-settings.yml @@ -0,0 +1,7 @@ +issue_key: 2350 +show_in_stores: true +platforms: + - android + - ios +en: Add explanation if push notification permissions are missing. +de: Es wird nun eine Erklärung angezeigt, wenn die Berechtigungen für Push-Benachrichtigungen fehlen. diff --git a/translations/translations.json b/translations/translations.json index c0f8b88f24..1ea0ec636d 100644 --- a/translations/translations.json +++ b/translations/translations.json @@ -2338,6 +2338,7 @@ "notSupportedByDevice": "Diese Funktion wird auf diesem Gerät nicht unterstützt.", "languageSwitchFailedTitle": "Leider ist der Sprachwechsel fehlgeschlagen.", "languageSwitchFailedMessage": "Die ausgewählte Sprache ist nicht offline verfügbar. Eine aktive Internetverbinding ist notwendig.", + "noPushNotificatidbonPermission": "Berechtigung erforderlich", "noCalendarPermission": "Der Zugriff auf den Kalender ist nicht erlaubt.", "noCalendarFound": "Es wurde kein geeigneter Kalender gefunden." }, @@ -2618,6 +2619,7 @@ "notSupportedByDevice": "This function is not supported on this device.", "languageSwitchFailedTitle": "Unfortunately, changing the language failed.", "languageSwitchFailedMessage": "The selected language is not available if you are offline. An active internet connection is required.", + "noPushNotificationPermission": "Permission required", "noCalendarPermission": "Access to the calendar is not permitted.", "noCalendarFound": "No suitable calendar was found." }, @@ -3617,7 +3619,6 @@ "chooseCalendar": "Kalender-Auswahl", "added": "Hinzugefügt", "goToCalendar": "Zum Kalender", - "settings": "Einstellungen", "recurring": "wiederholend", "today": "heute", "todayRecurring": "heute, wiederholend", @@ -3647,7 +3648,6 @@ "chooseCalendar": "የቀን መቁጠሪያን ይምረጡ", "added": "ታክሏል", "goToCalendar": "ወደ ቀን መቁጠሪያ ይሂዱ", - "settings": "ቅንብሮች", "recurring": "ተደጋጋሚ", "today": "ዛሬ", "todayRecurring": "ዛሬ፣ ተደጋጋሚ", @@ -3677,7 +3677,6 @@ "chooseCalendar": "اختر تقويمًا", "added": "تمت الإضافة", "goToCalendar": "إلى التقويم", - "settings": "أوضاع الضبط", "recurring": "مكرر", "today": "اليوم", "todayRecurring": "اليوم، مكرر", @@ -3707,7 +3706,6 @@ "chooseCalendar": "Избери календар", "added": "Добавен", "goToCalendar": "Към календара", - "settings": "Настройки", "recurring": "повтарящ се", "today": "днес", "todayRecurring": "днес, повтарящ се", @@ -3737,7 +3735,6 @@ "chooseCalendar": "ساڵنامەیەک هەڵبژێرە", "added": "زیادکرا", "goToCalendar": "دەسپێگەیشتن بە ساڵنامە", - "settings": "ڕێکخستنەکان", "recurring": "دووپاتە", "today": "ئەمڕۆ", "todayRecurring": "ئەمڕۆ، دووپاتە", @@ -3767,7 +3764,6 @@ "chooseCalendar": "Výběr kalendáře", "added": "Přidáno", "goToCalendar": "Do kalendáře", - "settings": "Nastavení", "recurring": "opakování", "today": "dnes", "todayRecurring": "dnes, opakování", @@ -3797,7 +3793,6 @@ "chooseCalendar": "Valg af kalender", "added": "Tilføjet", "goToCalendar": "Til kalenderen", - "settings": "Indstillinger", "recurring": "gentagende", "today": "i dag", "todayRecurring": "i dag og gentagende", @@ -3827,7 +3822,6 @@ "chooseCalendar": "Επιλέξτε ένα ημερολόγιο", "added": "Προστέθηκε", "goToCalendar": "Μετάβαση στο ημερολόγιο", - "settings": "Ρυθμίσεις", "recurring": "επαναλαμβάνεται", "today": "σήμερα", "todayRecurring": "σήμερα, επαναλαμβάνεται", @@ -3857,7 +3851,6 @@ "chooseCalendar": "Calendar choice", "added": "Added", "goToCalendar": "Go to calendar", - "settings": "Settings", "recurring": "recurring", "today": "today", "todayRecurring": "today, recurring", @@ -3887,7 +3880,6 @@ "chooseCalendar": "Elije un calendario", "added": "Se añadió", "goToCalendar": "al calendario", - "settings": "Ajustes", "recurring": "repetitivo", "today": "hoy", "todayRecurring": "hoy, repetitivo", @@ -3917,7 +3909,6 @@ "chooseCalendar": "Valitse kalenteri", "added": "Lisätty", "goToCalendar": "Kalenteriin", - "settings": "Asetukset", "recurring": "toistuva", "today": "tänään", "todayRecurring": "tänään, toistuva", @@ -3947,7 +3938,6 @@ "chooseCalendar": "Choisis un calendrier", "added": "Ajouté", "goToCalendar": "Accéder au calendrier", - "settings": "Réglages", "recurring": "répétitif", "today": "aujourd’hui", "todayRecurring": "aujourd’hui, répétitif", @@ -3977,7 +3967,6 @@ "chooseCalendar": "Izaberi kalendar", "added": "Dodano", "goToCalendar": "Na kalendar", - "settings": "Postavke", "recurring": "ponavljajući", "today": "danas", "todayRecurring": "danas, ponavljajući", @@ -4007,7 +3996,6 @@ "chooseCalendar": "Válasszon ki egy naptárat", "added": "Hozzáadva", "goToCalendar": "A naptárhoz", - "settings": "Beállítások", "recurring": "ismétlődő", "today": "ma", "todayRecurring": "ma, ismétlődve", @@ -4037,7 +4025,6 @@ "chooseCalendar": "Seleziona un calendario", "added": "Aggiunto", "goToCalendar": "Al calendario", - "settings": "Impostazioni", "recurring": "ricorrente", "today": "oggi", "todayRecurring": "oggi, ricorrente", @@ -4067,7 +4054,6 @@ "chooseCalendar": "აირჩიე კალენდარი", "added": "დამატებულია", "goToCalendar": "კალენდარზე გადასვლა", - "settings": "პარამეტრები", "recurring": "განმეორებით", "today": "დღეს", "todayRecurring": "დღეს, განმეორებით", @@ -4097,7 +4083,6 @@ "chooseCalendar": "Rojhejmêrekê bibijêre", "added": "Zêdekirin", "goToCalendar": "Li rojhejmêrê", - "settings": "Eyarkirin", "recurring": "Dubarebûyî", "today": "Îro", "todayRecurring": "Îro, dubarebûyî", @@ -4127,7 +4112,6 @@ "chooseCalendar": "Избери календар", "added": "Додадено", "goToCalendar": "Кон календарот", - "settings": "Поставки", "recurring": "повторувачки", "today": "утре", "todayRecurring": "утре, повторувачки", @@ -4157,7 +4141,6 @@ "chooseCalendar": "Selecteer een kalender", "added": "Toegevoegd", "goToCalendar": "Naar de kalender", - "settings": "Instellingen", "recurring": "herhalend", "today": "vandaag", "todayRecurring": "vandaag, herhalend", @@ -4187,7 +4170,6 @@ "chooseCalendar": "Filannoo Kaalanderii", "added": "Dabalameera", "goToCalendar": "Gara kaalanderii", - "settings": "Saajoo", "recurring": "Irra deddeebii", "today": "Hara", "todayRecurring": "Irra deebii haraa", @@ -4217,7 +4199,6 @@ "chooseCalendar": "یک تقویم را انتخاب کنید", "added": "افزوده شد", "goToCalendar": "دسترسی به تقویم", - "settings": "تنظیمات", "recurring": "تکراری", "today": "امروز", "todayRecurring": "امروز، تکراری", @@ -4247,7 +4228,6 @@ "chooseCalendar": "Wybierz kalendarz", "added": "Dodano", "goToCalendar": "Do kalendarza", - "settings": "Ustawienia", "recurring": "powtarzający się", "today": "dzisiaj", "todayRecurring": "dzisiaj, powtarzający się", @@ -4277,7 +4257,6 @@ "chooseCalendar": "یک تقویم را انتخاب کنید", "added": "اضافه شد", "goToCalendar": "دسترسی به تقویم", - "settings": "تنظیمات", "recurring": "تکراری", "today": "امروز", "todayRecurring": "امروز، تکراری", @@ -4307,7 +4286,6 @@ "chooseCalendar": "يوه جنتري غوره کړئ", "added": "اضافه شو", "goToCalendar": "جنتري ته لاسرسی", - "settings": "تنظيمات", "recurring": "تکراري", "today": "نن ورځ", "todayRecurring": "نن ورځ، تکراري", @@ -4337,7 +4315,6 @@ "chooseCalendar": "Selecione um calendário", "added": "Adicionado", "goToCalendar": "Para o calendário", - "settings": "Definições", "recurring": "repetitivo", "today": "hoje", "todayRecurring": "hoje, repetitivo", @@ -4367,7 +4344,6 @@ "chooseCalendar": "Selectați un calendar", "added": "Adăugat", "goToCalendar": "La calendar", - "settings": "Setări", "recurring": "repetarea", "today": "astăzi", "todayRecurring": "astăzi, repetând", @@ -4397,7 +4373,6 @@ "chooseCalendar": "Выбери календарь", "added": "Добавлено", "goToCalendar": "К календарю", - "settings": "Настройки", "recurring": "периодически", "today": "сегодня", "todayRecurring": "сегодня, периодически", @@ -4427,7 +4402,6 @@ "chooseCalendar": "Výber kalendára", "added": "Pridané", "goToCalendar": "Ku kalendáru", - "settings": "Nastavenia", "recurring": "opakujúce sa", "today": "dnes", "todayRecurring": "dnes, opakujúce sa", @@ -4457,7 +4431,6 @@ "chooseCalendar": "Dooro jadwalka", "added": "Ku daray", "goToCalendar": "Jadwalka", - "settings": "Dejinta", "recurring": "Soo noqnoqda", "today": "Maanta", "todayRecurring": "Maanta, soo noqnoqonaysa", @@ -4487,7 +4460,6 @@ "chooseCalendar": "Zgjidh një kalendar", "added": "U shtua", "goToCalendar": "Shko te kalendari", - "settings": "Cilësimet", "recurring": "periodik", "today": "sot", "todayRecurring": "sot, periodik", @@ -4517,7 +4489,6 @@ "chooseCalendar": "Изабери календар", "added": "Додато", "goToCalendar": "На календар", - "settings": "Подешавања", "recurring": "понављајући", "today": "данас", "todayRecurring": "данас, понављајући", @@ -4547,7 +4518,6 @@ "chooseCalendar": "Izaberi kalendar", "added": "Dodato", "goToCalendar": "Na kalendar", - "settings": "Podešavanja", "recurring": "ponavljajući", "today": "danas", "todayRecurring": "danas, ponavljajući", @@ -4577,7 +4547,6 @@ "chooseCalendar": "ዓውደ ኣዋርሕ ምረጽ", "added": "ተወሰኸ", "goToCalendar": "ናብ ዓውደ ኣዋርሕ", - "settings": "ቅጥዕታት", "recurring": "ተደጋጋሚ", "today": "ሎምዓንቲ", "todayRecurring": "ሎሚ፣ ተደጋጋሚ", @@ -4607,7 +4576,6 @@ "chooseCalendar": "Bir takvim seç", "added": "Eklendi", "goToCalendar": "Takvime git", - "settings": "Ayarlar", "recurring": "tekrarlayan", "today": "bugün", "todayRecurring": "bugün, tekrarlayan", @@ -4637,7 +4605,6 @@ "chooseCalendar": "Виберіть календар", "added": "Додано", "goToCalendar": "До календаря", - "settings": "Налаштування", "recurring": "періодичні", "today": "сьогодні", "todayRecurring": "сьогодні, періодичні", @@ -4667,7 +4634,6 @@ "chooseCalendar": "ایک کیلنڈر منتخب کریں", "added": "شامل کیا گیا", "goToCalendar": "کیلنڈر پر جائیں", - "settings": "ترتیبات", "recurring": "مکرر", "today": "آج", "todayRecurring": "آج، مکرر", @@ -4697,7 +4663,6 @@ "chooseCalendar": "选择日历", "added": "添加到日历", "goToCalendar": "转到日历", - "settings": "设置", "recurring": "重复", "today": "今天", "todayRecurring": "今天,重复", From e43f924079d390fa6276001d9db25d74196e5745 Mon Sep 17 00:00:00 2001 From: ztefanie Date: Thu, 17 Oct 2024 13:53:19 +0200 Subject: [PATCH 02/29] 2945: Distinguish automatic and counselor messages --- assets/icons/chatbot-bot.svg | 4 ++++ assets/icons/chatbot-person.svg | 4 ++++ .../api/endpoints/createChatMessagesEndpoint.ts | 1 + shared/api/models/ChatMessageModel.ts | 10 ++++++++-- shared/api/types.ts | 1 + web/src/assets/index.ts | 4 ++++ web/src/components/ChatMessage.tsx | 17 ++++++++++++----- 7 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 assets/icons/chatbot-bot.svg create mode 100644 assets/icons/chatbot-person.svg diff --git a/assets/icons/chatbot-bot.svg b/assets/icons/chatbot-bot.svg new file mode 100644 index 0000000000..31cbd00b2a --- /dev/null +++ b/assets/icons/chatbot-bot.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/chatbot-person.svg b/assets/icons/chatbot-person.svg new file mode 100644 index 0000000000..03fd461865 --- /dev/null +++ b/assets/icons/chatbot-person.svg @@ -0,0 +1,4 @@ + + + + diff --git a/shared/api/endpoints/createChatMessagesEndpoint.ts b/shared/api/endpoints/createChatMessagesEndpoint.ts index 718c803e57..d98387c89b 100644 --- a/shared/api/endpoints/createChatMessagesEndpoint.ts +++ b/shared/api/endpoints/createChatMessagesEndpoint.ts @@ -25,6 +25,7 @@ export default (baseUrl: string): Endpoint> id: chatMessage.id, body: chatMessage.body, userIsAuthor: chatMessage.user_is_author, + automaticAnswer: chatMessage.automatic_answer, }), ), ) diff --git a/shared/api/models/ChatMessageModel.ts b/shared/api/models/ChatMessageModel.ts index cd367bf351..19dc54a059 100644 --- a/shared/api/models/ChatMessageModel.ts +++ b/shared/api/models/ChatMessageModel.ts @@ -2,12 +2,14 @@ class ChatMessageModel { _id: number _body: string _userIsAuthor: boolean + _automaticAnswer: boolean - constructor(params: { id: number; body: string; userIsAuthor: boolean }) { - const { id, body, userIsAuthor } = params + constructor(params: { id: number; body: string; userIsAuthor: boolean; automaticAnswer: boolean }) { + const { id, body, userIsAuthor, automaticAnswer } = params this._id = id this._body = body this._userIsAuthor = userIsAuthor + this._automaticAnswer = automaticAnswer } get id(): number { @@ -21,6 +23,10 @@ class ChatMessageModel { get userIsAuthor(): boolean { return this._userIsAuthor } + + get isAutomaticAnswer(): boolean { + return this._automaticAnswer + } } export default ChatMessageModel diff --git a/shared/api/types.ts b/shared/api/types.ts index a6e5193f7d..3167ea21a6 100644 --- a/shared/api/types.ts +++ b/shared/api/types.ts @@ -77,6 +77,7 @@ export type JsonChatMessageType = { id: number body: string user_is_author: boolean + automatic_answer: boolean } export type JsonChatMessagesType = { messages: JsonChatMessageType[] diff --git a/web/src/assets/index.ts b/web/src/assets/index.ts index 406ccc500c..40c0799d56 100644 --- a/web/src/assets/index.ts +++ b/web/src/assets/index.ts @@ -13,6 +13,8 @@ import CalendarTodayIcon from '../../../assets/icons/calendar-today.svg' import CalendarIcon from '../../../assets/icons/calendar.svg' import CategoriesIcon from '../../../assets/icons/categories.svg' import ChatIcon from '../../../assets/icons/chat.svg' +import ChatbotBot from '../../../assets/icons/chatbot-bot.svg' +import ChatbotPerson from '../../../assets/icons/chatbot-person.svg' import ClockIcon from '../../../assets/icons/clock.svg' import CloseIcon from '../../../assets/icons/close.svg' import CopyIcon from '../../../assets/icons/copy.svg' @@ -66,6 +68,8 @@ export { CalendarTodayIcon, CalendarTodayRecurringIcon, CategoriesIcon, + ChatbotPerson, + ChatbotBot, ChatIcon, ClockIcon, CloseIcon, diff --git a/web/src/components/ChatMessage.tsx b/web/src/components/ChatMessage.tsx index 06e328a322..f31dd17073 100644 --- a/web/src/components/ChatMessage.tsx +++ b/web/src/components/ChatMessage.tsx @@ -5,6 +5,7 @@ import styled from 'styled-components' import ChatMessageModel from 'shared/api/models/ChatMessageModel' +import { ChatbotBot, ChatbotPerson } from '../assets' import buildConfig from '../constants/buildConfig' import RemoteContent from './RemoteContent' import Icon from './base/Icon' @@ -51,15 +52,21 @@ type ChatMessageProps = { message: ChatMessageModel; showIcon: boolean } const ChatMessage = ({ message, showIcon }: ChatMessageProps): ReactElement => { // TODO 2799 Check if Remote content is really needed here or how external links will be delivered via api - const { icons } = buildConfig() const navigate = useNavigate() const { t } = useTranslation('chat') - const { body, userIsAuthor } = message + const { body, userIsAuthor, isAutomaticAnswer } = message + + const getIcon = (userIsAuthor: boolean, isAutomaticAnswer: boolean): ReactElement => { + if (userIsAuthor) { + return {t('user')} + } + const icon = isAutomaticAnswer ? ChatbotBot : ChatbotPerson + return + } + return ( - - {userIsAuthor ? {t('user')} : } - + {getIcon(userIsAuthor, isAutomaticAnswer)} From c68c664cfbc6058109f9e23845f536f149ed630a Mon Sep 17 00:00:00 2001 From: Simon Kleinle Date: Mon, 21 Oct 2024 14:17:03 +0200 Subject: [PATCH 03/29] 2731: Add lint rule for array style --- .eslintrc.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index 3718e06eed..b222ab6fe5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -113,6 +113,12 @@ module.exports = { allowNullableString: true, }, ], + '@typescript-eslint/array-type': [ + 'error', + { + default: 'array', + }, + ], '@typescript-eslint/switch-exhaustiveness-check': 'error', '@typescript-eslint/no-non-null-assertion': 'error', From 9eb0687a9c73d62ebccb226da461f2238fe0de81 Mon Sep 17 00:00:00 2001 From: Simon Kleinle Date: Mon, 21 Oct 2024 14:37:19 +0200 Subject: [PATCH 04/29] 2577: Add warningColor into config --- build-configs/common/theme/colors.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/build-configs/common/theme/colors.ts b/build-configs/common/theme/colors.ts index 3b6d266ac0..52c2e3859c 100644 --- a/build-configs/common/theme/colors.ts +++ b/build-configs/common/theme/colors.ts @@ -30,5 +30,6 @@ export const commonLightColors = { positiveHighlight: '#188038', negativeHighlight: '#8b0000', invalidInput: '#B3261E', + warningColor: '#FFA726', linkColor: '#0b57d0', } From 6c54b137a456c75fa2cc1694c2b9be104ac00b56 Mon Sep 17 00:00:00 2001 From: Simon Kleinle Date: Wed, 23 Oct 2024 13:33:14 +0200 Subject: [PATCH 05/29] 2577: Add missing declaration and use warningColor in project --- build-configs/common/theme/colors.ts | 1 + web/src/components/Note.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build-configs/common/theme/colors.ts b/build-configs/common/theme/colors.ts index 52c2e3859c..13d32983bf 100644 --- a/build-configs/common/theme/colors.ts +++ b/build-configs/common/theme/colors.ts @@ -14,6 +14,7 @@ export type ColorsType = { positiveHighlight: string negativeHighlight: string invalidInput: string + warningColor: string linkColor: string } export const commonLightColors = { diff --git a/web/src/components/Note.tsx b/web/src/components/Note.tsx index db1030528e..9105cae392 100644 --- a/web/src/components/Note.tsx +++ b/web/src/components/Note.tsx @@ -6,7 +6,7 @@ import Icon from './base/Icon' const NoteContainer = styled.div` display: flex; - background-color: ${props => props.theme.colors.themeColor}; + background-color: ${props => props.theme.colors.warningColor}; padding: 12px; gap: 12px; align-items: center; From 302a0b6fbe87515e2a42d81f3a2ee6fd3f9763d4 Mon Sep 17 00:00:00 2001 From: Simon Kleinle Date: Wed, 23 Oct 2024 14:36:48 +0200 Subject: [PATCH 06/29] 2577: Change array style to new linting rule in project --- build-configs/BuildConfigType.ts | 4 +- e2e-tests/native/test/helpers/Selector.ts | 2 +- e2e-tests/web/wdio.conf.ts | 2 +- .../src/__mocks__/react-native-blob-util.ts | 4 +- native/src/components/CitySelector.tsx | 2 +- native/src/components/CustomHeaderButtons.tsx | 4 +- native/src/components/List.tsx | 2 +- native/src/components/NearbyCities.tsx | 2 +- native/src/components/News.tsx | 2 +- native/src/components/Selector.tsx | 2 +- native/src/components/__tests__/News.spec.tsx | 2 +- native/src/constants/NavigationTypes.ts | 4 +- .../navigation/navigateToLanguageChange.ts | 4 +- native/src/routes/Events.tsx | 2 +- native/src/routes/Intro.tsx | 2 +- native/src/routes/Pois.tsx | 2 +- native/src/routes/SearchModal.tsx | 2 +- native/src/utils/AppSettings.ts | 2 +- native/src/utils/DataContainer.ts | 16 +- native/src/utils/DatabaseConnector.ts | 18 +- native/src/utils/DefaultDataContainer.ts | 49 ++-- native/src/utils/NativeLanguageDetector.ts | 2 +- native/src/utils/ResourceURLFinder.ts | 4 +- native/src/utils/createSettingsSections.ts | 2 +- native/src/utils/helpers.ts | 4 +- native/src/utils/loadResourceCache.ts | 2 +- .../api/endpoints/createCategoriesEndpoint.ts | 2 +- .../createCategoryChildrenEndpoint.ts | 6 +- .../createCategoryParentsEndpoint.ts | 6 +- .../endpoints/createChatMessagesEndpoint.ts | 23 +- shared/api/endpoints/createEventsEndpoint.ts | 89 +++--- .../createLocalNewsElementEndpoint.ts | 2 +- .../api/endpoints/createLocalNewsEndpoint.ts | 27 +- shared/api/endpoints/createPOIsEndpoint.ts | 77 +++--- .../createSprungbrettJobsEndpoint.ts | 29 +- .../endpoints/createTunewsElementEndpoint.ts | 2 +- shared/api/endpoints/createTunewsEndpoint.ts | 29 +- .../createTunewsLanguagesEndpoint.ts | 6 +- .../testing/CategoriesMapModelBuilder.ts | 2 +- .../api/endpoints/testing/CityModelBuilder.ts | 2 +- .../endpoints/testing/EventModelBuilder.ts | 2 +- .../endpoints/testing/LanguageModelBuilder.ts | 2 +- .../api/endpoints/testing/NewsModelBuilder.ts | 6 +- .../api/endpoints/testing/PoiModelBuilder.ts | 2 +- shared/api/models/CategoriesMapModel.ts | 10 +- shared/api/models/CityModel.ts | 2 +- shared/api/models/TunewsModel.ts | 13 +- shared/api/types.ts | 2 +- shared/routes/InternalPathnameParser.ts | 2 +- shared/routes/pathname.ts | 2 +- tools/yarn.lock | 258 ++++-------------- web/src/components/Breadcrumbs.tsx | 2 +- web/src/components/CityContentHeader.tsx | 6 +- web/src/components/CityContentLayout.tsx | 2 +- web/src/components/CitySelector.tsx | 2 +- web/src/components/Footer.tsx | 2 +- web/src/components/Header.tsx | 6 +- .../components/HeaderLanguageSelectorItem.tsx | 2 +- web/src/components/Helmet.tsx | 2 +- web/src/components/JsonLdBreadcrumbs.tsx | 4 +- web/src/components/KebabMenu.tsx | 2 +- web/src/components/LanguageFailure.tsx | 2 +- web/src/components/LanguageSelector.tsx | 2 +- web/src/components/List.tsx | 2 +- web/src/components/LocalNewsList.tsx | 2 +- web/src/components/Selector.tsx | 2 +- web/src/components/Tiles.tsx | 2 +- 67 files changed, 310 insertions(+), 478 deletions(-) diff --git a/build-configs/BuildConfigType.ts b/build-configs/BuildConfigType.ts index 3bb5b9d357..b8303e244e 100644 --- a/build-configs/BuildConfigType.ts +++ b/build-configs/BuildConfigType.ts @@ -52,9 +52,9 @@ export type CommonBuildConfigType = { // Host name of the web app, used for sharing, deep linking and social media previews. hostName: string // Hostnames from which resources are automatically downloaded for offline usage. - allowedHostNames: Array + allowedHostNames: string[] // Linked hosts that can may look similar https://chromium.googlesource.com/chromium/src/+/master/docs/security/lookalikes/lookalike-domains.md#automated-warning-removal - allowedLookalikes: Array + allowedLookalikes: string[] // Regex defining which urls to intercept as they are internal ones. supportedIframeSources: string[] internalLinksHijackPattern: string diff --git a/e2e-tests/native/test/helpers/Selector.ts b/e2e-tests/native/test/helpers/Selector.ts index f2c4d636a8..79278eb070 100644 --- a/e2e-tests/native/test/helpers/Selector.ts +++ b/e2e-tests/native/test/helpers/Selector.ts @@ -1,5 +1,5 @@ export class Selector { - private queries: Array = new Array() + private queries: string[] = new Array() public ByText(text: string): Selector { if (driver.isAndroid) { diff --git a/e2e-tests/web/wdio.conf.ts b/e2e-tests/web/wdio.conf.ts index 83fbd8874e..b6711e4bd3 100644 --- a/e2e-tests/web/wdio.conf.ts +++ b/e2e-tests/web/wdio.conf.ts @@ -1,7 +1,7 @@ import { browsers, ciCapabilities } from './capabilities.js' import waitForLocalhost from './waitForLocalhost.js' -const getCapabilities = (): Array => { +const getCapabilities = (): WebdriverIO.Capabilities[] => { if (process.env.CI) { return [ciCapabilities] } diff --git a/native/src/__mocks__/react-native-blob-util.ts b/native/src/__mocks__/react-native-blob-util.ts index 48fe48979f..5797b5e786 100644 --- a/native/src/__mocks__/react-native-blob-util.ts +++ b/native/src/__mocks__/react-native-blob-util.ts @@ -27,7 +27,7 @@ const existsMock = (file: string): Promise => { return Promise.resolve(exists || isParentOfExisting) } -const lsMock = (path: string): Promise> => { +const lsMock = (path: string): Promise => { const filesInPath = Object.keys(mockFiles).filter(filePath => filePath.startsWith(path)) return Promise.resolve(filesInPath) } @@ -58,7 +58,7 @@ export default { }, }, fs: { - ls: jest.fn>, [string]>(lsMock), + ls: jest.fn, [string]>(lsMock), exists: jest.fn, [string]>(existsMock), isDir: jest.fn, [string]>(async () => true), writeFile: jest.fn, [string, string, string]>(writeMockFile), diff --git a/native/src/components/CitySelector.tsx b/native/src/components/CitySelector.tsx index 819214f6cf..34b2454e8a 100644 --- a/native/src/components/CitySelector.tsx +++ b/native/src/components/CitySelector.tsx @@ -27,7 +27,7 @@ const SearchBar = styled.View` ` type CitySelectorProps = { - cities: Array + cities: CityModel[] navigateToDashboard: (city: CityModel) => void } diff --git a/native/src/components/CustomHeaderButtons.tsx b/native/src/components/CustomHeaderButtons.tsx index 8367de5e9d..31dae0478f 100644 --- a/native/src/components/CustomHeaderButtons.tsx +++ b/native/src/components/CustomHeaderButtons.tsx @@ -40,8 +40,8 @@ const onOverflowMenuPress = (cancelButtonLabel: string) => (props: OnOverflowMen const CustomHeaderButtons = (props: { cancelLabel: string - items: Array - overflowItems: Array + items: ReactNode[] + overflowItems: ReactNode[] }): ReactElement => { const { cancelLabel, items, overflowItems } = props const { t } = useTranslation('common') diff --git a/native/src/components/List.tsx b/native/src/components/List.tsx index 118d0f016b..5e3db382ca 100644 --- a/native/src/components/List.tsx +++ b/native/src/components/List.tsx @@ -10,7 +10,7 @@ const NoItemsMessage = styled.Text` ` type ListProps = { - items: Array + items: T[] noItemsMessage?: ReactElement | string renderItem: (props: { item: T; index: number }) => ReactElement Header?: ReactElement diff --git a/native/src/components/NearbyCities.tsx b/native/src/components/NearbyCities.tsx index a953b61461..d4a06bd02d 100644 --- a/native/src/components/NearbyCities.tsx +++ b/native/src/components/NearbyCities.tsx @@ -31,7 +31,7 @@ const StyledIcon = styled(Icon)` ` type NearbyCitiesProps = { - cities: Array + cities: CityModel[] navigateToDashboard: (city: CityModel) => void filterText: string } diff --git a/native/src/components/News.tsx b/native/src/components/News.tsx index 98b7f55885..a33d6edea3 100644 --- a/native/src/components/News.tsx +++ b/native/src/components/News.tsx @@ -37,7 +37,7 @@ const getPageTitle = ( return t('localNews.pageTitle') } -type NewsModelsType = Array +type NewsModelsType = (LocalNewsModel | TunewsModel)[] type NewsProps = { news: NewsModelsType diff --git a/native/src/components/Selector.tsx b/native/src/components/Selector.tsx index 8185e4f1dc..10253c02b0 100644 --- a/native/src/components/Selector.tsx +++ b/native/src/components/Selector.tsx @@ -15,7 +15,7 @@ export const Wrapper = styled.View` ` type SelectorProps = { - items: Array + items: SelectorItemModel[] selectedItemCode: string | null } diff --git a/native/src/components/__tests__/News.spec.tsx b/native/src/components/__tests__/News.spec.tsx index 78ca6ee904..461dc16584 100644 --- a/native/src/components/__tests__/News.spec.tsx +++ b/native/src/components/__tests__/News.spec.tsx @@ -68,7 +68,7 @@ describe('News', () => { localNewsEnabled = true, }: { newsId?: number | null - data?: Array + data?: (LocalNewsModel | TunewsModel)[] loadingMore?: boolean selectedNewsType?: TuNewsType | LocalNewsType tuNewsEnabled?: boolean diff --git a/native/src/constants/NavigationTypes.ts b/native/src/constants/NavigationTypes.ts index 0e888387c6..1f452a1c05 100644 --- a/native/src/constants/NavigationTypes.ts +++ b/native/src/constants/NavigationTypes.ts @@ -100,8 +100,8 @@ export type RoutesParamsType = { } [LICENSES_ROUTE]: undefined [CHANGE_LANGUAGE_MODAL_ROUTE]: { - languages: Array - availableLanguages: Array + languages: LanguageModel[] + availableLanguages: string[] } [PDF_VIEW_MODAL_ROUTE]: { url: string diff --git a/native/src/navigation/navigateToLanguageChange.ts b/native/src/navigation/navigateToLanguageChange.ts index df276c860c..7bd627487b 100644 --- a/native/src/navigation/navigateToLanguageChange.ts +++ b/native/src/navigation/navigateToLanguageChange.ts @@ -10,8 +10,8 @@ const navigateToLanguageChange = ({ availableLanguages, }: { navigation: NavigationProps - languages: Array - availableLanguages: Array + languages: LanguageModel[] + availableLanguages: string[] }): void => { sendTrackingSignal({ signal: { diff --git a/native/src/routes/Events.tsx b/native/src/routes/Events.tsx index 88aab065d0..26fa75fffa 100644 --- a/native/src/routes/Events.tsx +++ b/native/src/routes/Events.tsx @@ -32,7 +32,7 @@ const PageDetailsContainer = styled.View` export type EventsProps = { slug?: string - events: Array + events: EventModel[] cityModel: CityModel language: string navigateTo: (routeInformation: RouteInformationType) => void diff --git a/native/src/routes/Intro.tsx b/native/src/routes/Intro.tsx index 4dc44f1cee..4bd30d19e4 100644 --- a/native/src/routes/Intro.tsx +++ b/native/src/routes/Intro.tsx @@ -124,7 +124,7 @@ const Intro = ({ route, navigation }: IntroProps): ReactElement => { const renderSlide = ({ item }: { item: SlideContentType }) => - const onViewableItemsChanged = useCallback(({ viewableItems }: { viewableItems: Array }) => { + const onViewableItemsChanged = useCallback(({ viewableItems }: { viewableItems: ViewToken[] }) => { const viewableItem = viewableItems[0] if (viewableItem) { if (viewableItem.index !== null) { diff --git a/native/src/routes/Pois.tsx b/native/src/routes/Pois.tsx index e9843af558..8ef2ff83a2 100644 --- a/native/src/routes/Pois.tsx +++ b/native/src/routes/Pois.tsx @@ -46,7 +46,7 @@ const getBottomSheetSnapPoints = (deviceHeight: number): [number, number, number ] type PoisProps = { - pois: Array + pois: PoiModel[] cityModel: CityModel language: string refresh: () => void diff --git a/native/src/routes/SearchModal.tsx b/native/src/routes/SearchModal.tsx index 3ab2862e2a..f5480269d5 100644 --- a/native/src/routes/SearchModal.tsx +++ b/native/src/routes/SearchModal.tsx @@ -23,7 +23,7 @@ const Wrapper = styled.View` ` export type SearchModalProps = { - allPossibleResults: Array + allPossibleResults: SearchResult[] languageCode: string cityCode: string closeModal: (query: string) => void diff --git a/native/src/utils/AppSettings.ts b/native/src/utils/AppSettings.ts index 4f1b776d12..8f650dfae8 100644 --- a/native/src/utils/AppSettings.ts +++ b/native/src/utils/AppSettings.ts @@ -14,7 +14,7 @@ export type SettingsType = { apiUrlOverride: string | null jpalTrackingEnabled: boolean | null jpalTrackingCode: string | null - jpalSignals: Array + jpalSignals: SignalType[] externalSourcePermissions: ExternalSourcePermissions } export const defaultSettings: SettingsType = { diff --git a/native/src/utils/DataContainer.ts b/native/src/utils/DataContainer.ts index 0f361347fe..b319476b34 100644 --- a/native/src/utils/DataContainer.ts +++ b/native/src/utils/DataContainer.ts @@ -15,24 +15,24 @@ export type DataContainer = { * Returns an Array of PoiModels. * @throws Will throw an error if the array is null. */ - getPois: (city: string, language: string) => Promise> + getPois: (city: string, language: string) => Promise /** * Sets the pois and persist them ? */ - setPois: (city: string, language: string, pois: Array) => Promise + setPois: (city: string, language: string, pois: PoiModel[]) => Promise /** * Returns an Array of CityModels. * @throws Will throw an error if the array is null. */ - getCities: () => Promise> + getCities: () => Promise /** * Sets the cities but does not persist them. * For now switching cities when offline is not possible. */ - setCities: (cities: Array) => Promise + setCities: (cities: CityModel[]) => Promise /** * Returns the CategoriesMapModel. @@ -49,23 +49,23 @@ export type DataContainer = { * Returns an Array of events. * @throws Will throw an error if the array is null. */ - getEvents: (city: string, language: string) => Promise> + getEvents: (city: string, language: string) => Promise /** * Sets the events and persists them. */ - setEvents: (city: string, language: string, events: Array) => Promise + setEvents: (city: string, language: string, events: EventModel[]) => Promise /** * Returns an Array of local news. * @throws Will throw an error if the array is null. */ - getLocalNews: (city: string, language: string) => Promise> + getLocalNews: (city: string, language: string) => Promise /** * Sets the local news and persists them. */ - setLocalNews: (city: string, language: string, events: Array) => Promise + setLocalNews: (city: string, language: string, events: LocalNewsModel[]) => Promise /** * Returns the ResourceCache. diff --git a/native/src/utils/DatabaseConnector.ts b/native/src/utils/DatabaseConnector.ts index 561bdc8a7c..8b2ad9e728 100644 --- a/native/src/utils/DatabaseConnector.ts +++ b/native/src/utils/DatabaseConnector.ts @@ -54,7 +54,7 @@ type ContentCategoryJsonType = { thumbnail: string | null available_languages: Record parent_path: string - children: Array + children: string[] order: number organization: { name: string @@ -279,7 +279,7 @@ class DatabaseConnector { this._storeMetaCities(metaData) } - async _deleteMetaOfCities(cities: Array): Promise { + async _deleteMetaOfCities(cities: string[]): Promise { const metaCities = await this._loadMetaCities() cities.forEach(city => delete metaCities[city]) await this._storeMetaCities(metaCities) @@ -342,7 +342,7 @@ class DatabaseConnector { await this.writeFile(path, JSON.stringify(citiesMetaJson)) } - async loadLastUsages(): Promise> { + async loadLastUsages(): Promise { const metaData = await this._loadMetaCities() return map(metaData, (value, key) => ({ city: key, @@ -437,7 +437,7 @@ class DatabaseConnector { return this.readFile(path, mapCategoriesJson) } - async storePois(pois: Array, context: DatabaseContext): Promise { + async storePois(pois: PoiModel[], context: DatabaseContext): Promise { const jsonModels = pois.map( (poi: PoiModel): ContentPoiJsonType => ({ path: poi.path, @@ -484,7 +484,7 @@ class DatabaseConnector { await this.writeFile(this.getContentPath('pois', context), JSON.stringify(jsonModels)) } - async loadPois(context: DatabaseContext): Promise> { + async loadPois(context: DatabaseContext): Promise { const path = this.getContentPath('pois', context) const mapPoisJson = (json: ContentPoiJsonType[]) => json.map(jsonObject => { @@ -569,7 +569,7 @@ class DatabaseConnector { return this.readFile(path, mapLocalNewsJson) } - async storeCities(cities: Array): Promise { + async storeCities(cities: CityModel[]): Promise { const jsonModels = cities.map( (city: CityModel): ContentCityJsonType => ({ name: city.name, @@ -592,7 +592,7 @@ class DatabaseConnector { await this.writeFile(this.getCitiesPath(), JSON.stringify(jsonModels)) } - async loadCities(): Promise> { + async loadCities(): Promise { const path = this.getCitiesPath() const mapCityJson = (json: ContentCityJsonType[]) => json.map( @@ -619,7 +619,7 @@ class DatabaseConnector { return this.readFile(path, mapCityJson) } - async storeEvents(events: Array, context: DatabaseContext): Promise { + async storeEvents(events: EventModel[], context: DatabaseContext): Promise { const jsonModels = events.map( (event: EventModel): ContentEventJsonType => ({ path: event.path, @@ -663,7 +663,7 @@ class DatabaseConnector { await this.writeFile(this.getContentPath('events', context), JSON.stringify(jsonModels)) } - async loadEvents(context: DatabaseContext): Promise> { + async loadEvents(context: DatabaseContext): Promise { const path = this.getContentPath('events', context) const mapEventsJson = (json: ContentEventJsonType[]) => json.map(jsonObject => { diff --git a/native/src/utils/DefaultDataContainer.ts b/native/src/utils/DefaultDataContainer.ts index e0fe9cad6c..4151ceb7ea 100644 --- a/native/src/utils/DefaultDataContainer.ts +++ b/native/src/utils/DefaultDataContainer.ts @@ -16,11 +16,11 @@ import DatabaseConnector from './DatabaseConnector' import { log } from './sentry' type CacheType = { - pois: Cache> - cities: Cache> - events: Cache> + pois: Cache + cities: Cache + events: Cache categories: Cache - localNews: Cache> + localNews: Cache resourceCache: Cache lastUpdate: Cache } @@ -33,21 +33,21 @@ class DefaultDataContainer implements DataContainer { constructor() { this._databaseConnector = new DatabaseConnector() this.caches = { - pois: new Cache>( + pois: new Cache( this._databaseConnector, (connector: DatabaseConnector, context: DatabaseContext) => connector.loadPois(context), - (value: Array, connector: DatabaseConnector, context: DatabaseContext) => + (value: PoiModel[], connector: DatabaseConnector, context: DatabaseContext) => connector.storePois(value, context), ), - cities: new Cache>( + cities: new Cache( this._databaseConnector, (connector: DatabaseConnector) => connector.loadCities(), - (value: Array, connector: DatabaseConnector) => connector.storeCities(value), + (value: CityModel[], connector: DatabaseConnector) => connector.storeCities(value), ), - events: new Cache>( + events: new Cache( this._databaseConnector, (connector: DatabaseConnector, context: DatabaseContext) => connector.loadEvents(context), - (value: Array, connector: DatabaseConnector, context: DatabaseContext) => + (value: EventModel[], connector: DatabaseConnector, context: DatabaseContext) => connector.storeEvents(value, context), ), categories: new Cache( @@ -94,7 +94,7 @@ class DefaultDataContainer implements DataContainer { return this.caches[key].isCached(context) } - getCities = async (): Promise> => { + getCities = async (): Promise => { const cache = this.caches.cities return cache.get(new DatabaseContext()) } @@ -105,15 +105,15 @@ class DefaultDataContainer implements DataContainer { return cache.get(context) } - getEvents = (city: string, language: string): Promise> => { + getEvents = (city: string, language: string): Promise => { const context = new DatabaseContext(city, language) - const cache: Cache> = this.caches.events + const cache: Cache = this.caches.events return cache.get(context) } - getPois = (city: string, language: string): Promise> => { + getPois = (city: string, language: string): Promise => { const context = new DatabaseContext(city, language) - const cache: Cache> = this.caches.pois + const cache: Cache = this.caches.pois return cache.get(context) } @@ -143,9 +143,9 @@ class DefaultDataContainer implements DataContainer { await cache.cache(categories, context) } - setPois = async (city: string, language: string, pois: Array): Promise => { + setPois = async (city: string, language: string, pois: PoiModel[]): Promise => { const context = new DatabaseContext(city, language) - const cache: Cache> = this.caches.pois + const cache: Cache = this.caches.pois await cache.cache(pois, context) } @@ -155,22 +155,21 @@ class DefaultDataContainer implements DataContainer { await cache.cache(localNews, context) } - setCities = async (cities: Array): Promise => { + setCities = async (cities: CityModel[]): Promise => { const cache = this.caches.cities await cache.cache(cities, new DatabaseContext()) } - setEvents = async (city: string, language: string, events: Array): Promise => { + setEvents = async (city: string, language: string, events: EventModel[]): Promise => { const context = new DatabaseContext(city, language) - const cache: Cache> = this.caches.events + const cache: Cache = this.caches.events await cache.cache(events, context) } - getFilePathsFromLanguageResourceCache(languageResourceCache: LanguageResourceCacheStateType): Array { - const pageResourceCaches: Array = Object.values(languageResourceCache) - return flatMap( - pageResourceCaches, - (file: PageResourceCacheStateType): Array => map(file, ({ filePath }) => filePath), + getFilePathsFromLanguageResourceCache(languageResourceCache: LanguageResourceCacheStateType): string[] { + const pageResourceCaches: PageResourceCacheStateType[] = Object.values(languageResourceCache) + return flatMap(pageResourceCaches, (file: PageResourceCacheStateType): string[] => + map(file, ({ filePath }) => filePath), ) } diff --git a/native/src/utils/NativeLanguageDetector.ts b/native/src/utils/NativeLanguageDetector.ts index 3896304886..db5aab9b37 100644 --- a/native/src/utils/NativeLanguageDetector.ts +++ b/native/src/utils/NativeLanguageDetector.ts @@ -23,7 +23,7 @@ const NativeLanguageDetector: LanguageDetectorModule = { ) return acc }, - [] as Array, + [] as (string | undefined)[], ) // Return the first supported languageTag or our fallback return supportedKeys.find(it => it !== undefined) ?? config.defaultFallback diff --git a/native/src/utils/ResourceURLFinder.ts b/native/src/utils/ResourceURLFinder.ts index 5beff7e5ac..f73f3b1a7b 100644 --- a/native/src/utils/ResourceURLFinder.ts +++ b/native/src/utils/ResourceURLFinder.ts @@ -24,9 +24,9 @@ type InputEntryType = { export default class ResourceURLFinder { _parser: Parser | null = null _foundUrls: Set = new Set() - _allowedHostNames: Array + _allowedHostNames: string[] - constructor(allowedHostNames: Array) { + constructor(allowedHostNames: string[]) { this._allowedHostNames = allowedHostNames } diff --git a/native/src/utils/createSettingsSections.ts b/native/src/utils/createSettingsSections.ts index c526f88ff4..7d50924307 100644 --- a/native/src/utils/createSettingsSections.ts +++ b/native/src/utils/createSettingsSections.ts @@ -59,7 +59,7 @@ const createSettingsSections = ({ navigation, settings, showSnackbar, -}: CreateSettingsSectionsProps): Readonly>> => [ +}: CreateSettingsSectionsProps): Readonly[]> => [ { title: null, data: [ diff --git a/native/src/utils/helpers.ts b/native/src/utils/helpers.ts index 12a42ca82c..463729647c 100644 --- a/native/src/utils/helpers.ts +++ b/native/src/utils/helpers.ts @@ -33,9 +33,9 @@ export const determineApiUrl = async (): Promise => { */ export const forEachTreeNode = ( root: T, - resolveChildren: (arg0: T) => Array, + resolveChildren: (arg0: T) => T[], depth: number, - nodeAction: (arg0: T, arg1: Array | null | undefined) => void, + nodeAction: (arg0: T, arg1: T[] | null | undefined) => void, ): void => { if (depth === 0) { nodeAction(root, null) diff --git a/native/src/utils/loadResourceCache.ts b/native/src/utils/loadResourceCache.ts index 4726fb3225..fae1bc7496 100644 --- a/native/src/utils/loadResourceCache.ts +++ b/native/src/utils/loadResourceCache.ts @@ -16,7 +16,7 @@ export type FetchMapTargetType = { urlHash: string } -export type FetchMapType = Record> +export type FetchMapType = Record const loadResourceCache = async ({ cityCode, diff --git a/shared/api/endpoints/createCategoriesEndpoint.ts b/shared/api/endpoints/createCategoriesEndpoint.ts index f9c1f83a2f..918a84ccf4 100644 --- a/shared/api/endpoints/createCategoriesEndpoint.ts +++ b/shared/api/endpoints/createCategoriesEndpoint.ts @@ -18,7 +18,7 @@ export default (baseUrl: string): Endpoint => .withParamsToUrlMapper( (params: ParamsType): string => `${baseUrl}/api/${API_VERSION}/${params.city}/${params.language}/pages/`, ) - .withMapper((json: Array, params: ParamsType): CategoriesMapModel => { + .withMapper((json: JsonCategoryType[], params: ParamsType): CategoriesMapModel => { const basePath = `/${params.city}/${params.language}` const categories = json.map(category => mapCategoryJson(category, basePath)) categories.push( diff --git a/shared/api/endpoints/createCategoryChildrenEndpoint.ts b/shared/api/endpoints/createCategoryChildrenEndpoint.ts index cb4f70d1d3..a520a89291 100644 --- a/shared/api/endpoints/createCategoryChildrenEndpoint.ts +++ b/shared/api/endpoints/createCategoryChildrenEndpoint.ts @@ -11,8 +11,8 @@ type ParamsType = { cityContentPath: string depth: number } -export default (baseUrl: string): Endpoint> => - new EndpointBuilder>(CATEGORY_CHILDREN_ENDPOINT_NAME) +export default (baseUrl: string): Endpoint => + new EndpointBuilder(CATEGORY_CHILDREN_ENDPOINT_NAME) .withParamsToUrlMapper((params: ParamsType): string => { const { city, language, cityContentPath, depth } = params const basePath = `/${city}/${language}` @@ -20,7 +20,7 @@ export default (baseUrl: string): Endpoint> => const query = basePath === cityContentPath ? '' : `&url=${params.cityContentPath}` return `${baseUrl}/api/${API_VERSION}/${params.city}/${params.language}/children/?depth=${depth}${query}` }) - .withMapper((json: Array, params: ParamsType): Array => { + .withMapper((json: JsonCategoryType[], params: ParamsType): CategoryModel[] => { const basePath = `/${params.city}/${params.language}` return json.map(category => mapCategoryJson(category, basePath)) }) diff --git a/shared/api/endpoints/createCategoryParentsEndpoint.ts b/shared/api/endpoints/createCategoryParentsEndpoint.ts index 868ea60936..97ad4fd9cb 100644 --- a/shared/api/endpoints/createCategoryParentsEndpoint.ts +++ b/shared/api/endpoints/createCategoryParentsEndpoint.ts @@ -13,8 +13,8 @@ type ParamsType = { language: string cityContentPath: string } -export default (baseUrl: string): Endpoint> => - new EndpointBuilder>(CATEGORY_PARENTS_ENDPOINT_NAME) +export default (baseUrl: string): Endpoint => + new EndpointBuilder(CATEGORY_PARENTS_ENDPOINT_NAME) .withParamsToUrlMapper((params: ParamsType): string => { const { city, language, cityContentPath } = params const basePath = `/${city}/${language}` @@ -25,7 +25,7 @@ export default (baseUrl: string): Endpoint> => return `${baseUrl}/api/${API_VERSION}/${city}/${language}/parents/?url=${cityContentPath}` }) - .withMapper((json: Array, params: ParamsType): Array => { + .withMapper((json: JsonCategoryType[], params: ParamsType): CategoryModel[] => { const basePath = `/${params.city}/${params.language}` const parents = json.map(category => mapCategoryJson(category, basePath)) parents.push( diff --git a/shared/api/endpoints/createChatMessagesEndpoint.ts b/shared/api/endpoints/createChatMessagesEndpoint.ts index 718c803e57..09b6470291 100644 --- a/shared/api/endpoints/createChatMessagesEndpoint.ts +++ b/shared/api/endpoints/createChatMessagesEndpoint.ts @@ -11,21 +11,20 @@ type ParamsType = { deviceId: string } -export default (baseUrl: string): Endpoint> => - new EndpointBuilder>(CHAT_ENDPOINT_NAME) +export default (baseUrl: string): Endpoint => + new EndpointBuilder(CHAT_ENDPOINT_NAME) .withParamsToUrlMapper( (params: ParamsType): string => `${baseUrl}/api/${API_VERSION}/${params.city}/${params.language}/${CHAT_ENDPOINT_NAME}/${params.deviceId}/`, ) - .withMapper( - (json: JsonChatMessagesType): Array => - json.messages.map( - chatMessage => - new ChatMessageModel({ - id: chatMessage.id, - body: chatMessage.body, - userIsAuthor: chatMessage.user_is_author, - }), - ), + .withMapper((json: JsonChatMessagesType): ChatMessageModel[] => + json.messages.map( + chatMessage => + new ChatMessageModel({ + id: chatMessage.id, + body: chatMessage.body, + userIsAuthor: chatMessage.user_is_author, + }), + ), ) .build() diff --git a/shared/api/endpoints/createEventsEndpoint.ts b/shared/api/endpoints/createEventsEndpoint.ts index ce94b40e5d..11408ebcba 100644 --- a/shared/api/endpoints/createEventsEndpoint.ts +++ b/shared/api/endpoints/createEventsEndpoint.ts @@ -38,57 +38,56 @@ const eventCompare = (event1: EventModel, event2: EventModel): number => { return event1.title.localeCompare(event2.title) } -export default (baseUrl: string): Endpoint> => - new EndpointBuilder>(EVENTS_ENDPOINT_NAME) +export default (baseUrl: string): Endpoint => + new EndpointBuilder(EVENTS_ENDPOINT_NAME) .withParamsToUrlMapper( (params: ParamsType): string => `${baseUrl}/api/${API_VERSION}/${params.city}/${params.language}/events/?combine_recurring=True`, ) - .withMapper( - (json: Array): Array => - json - .map((event: JsonEventType): EventModel => { - const eventData = event.event - const allDay = eventData.all_day - return new EventModel({ - path: event.path, - title: event.title, - content: event.content, - thumbnail: event.thumbnail, - date: new DateModel({ - startDate: DateTime.fromISO(eventData.start), - endDate: DateTime.fromISO(eventData.end), - allDay, - recurrenceRule: event.recurrence_rule ? rrulestr(event.recurrence_rule) : null, - }), - location: - event.location.id !== null - ? new LocationModel({ - id: event.location.id, - name: event.location.name, - address: event.location.address, - town: event.location.town, - postcode: event.location.postcode, - country: event.location.country, - latitude: event.location.latitude, - longitude: event.location.longitude, - }) - : null, - excerpt: decodeHTML(event.excerpt), - availableLanguages: mapAvailableLanguages(event.available_languages), - lastUpdate: DateTime.fromISO(event.last_updated), - featuredImage: event.featured_image - ? new FeaturedImageModel({ - description: event.featured_image.description, - thumbnail: event.featured_image.thumbnail[0], - medium: event.featured_image.medium[0], - large: event.featured_image.large[0], - full: event.featured_image.full[0], + .withMapper((json: JsonEventType[]): EventModel[] => + json + .map((event: JsonEventType): EventModel => { + const eventData = event.event + const allDay = eventData.all_day + return new EventModel({ + path: event.path, + title: event.title, + content: event.content, + thumbnail: event.thumbnail, + date: new DateModel({ + startDate: DateTime.fromISO(eventData.start), + endDate: DateTime.fromISO(eventData.end), + allDay, + recurrenceRule: event.recurrence_rule ? rrulestr(event.recurrence_rule) : null, + }), + location: + event.location.id !== null + ? new LocationModel({ + id: event.location.id, + name: event.location.name, + address: event.location.address, + town: event.location.town, + postcode: event.location.postcode, + country: event.location.country, + latitude: event.location.latitude, + longitude: event.location.longitude, }) : null, - poiPath: event.location_path, - }) + excerpt: decodeHTML(event.excerpt), + availableLanguages: mapAvailableLanguages(event.available_languages), + lastUpdate: DateTime.fromISO(event.last_updated), + featuredImage: event.featured_image + ? new FeaturedImageModel({ + description: event.featured_image.description, + thumbnail: event.featured_image.thumbnail[0], + medium: event.featured_image.medium[0], + large: event.featured_image.large[0], + full: event.featured_image.full[0], + }) + : null, + poiPath: event.location_path, }) - .sort(eventCompare), + }) + .sort(eventCompare), ) .build() diff --git a/shared/api/endpoints/createLocalNewsElementEndpoint.ts b/shared/api/endpoints/createLocalNewsElementEndpoint.ts index 3aac69916a..e4b90520b6 100644 --- a/shared/api/endpoints/createLocalNewsElementEndpoint.ts +++ b/shared/api/endpoints/createLocalNewsElementEndpoint.ts @@ -22,7 +22,7 @@ export default (baseUrl: string): Endpoint => (params: ParamsType): string => `${baseUrl}/api/${API_VERSION}/${params.city}/${params.language}/fcm/?id=${params.id}`, ) - .withMapper((localNews: Array, params: ParamsType): LocalNewsModel => { + .withMapper((localNews: JsonLocalNewsType[], params: ParamsType): LocalNewsModel => { const localNewsModel = localNews[0] if (!localNewsModel) { diff --git a/shared/api/endpoints/createLocalNewsEndpoint.ts b/shared/api/endpoints/createLocalNewsEndpoint.ts index dce0cadcdd..5667c20b04 100644 --- a/shared/api/endpoints/createLocalNewsEndpoint.ts +++ b/shared/api/endpoints/createLocalNewsEndpoint.ts @@ -12,23 +12,22 @@ type ParamsType = { city: string language: string } -export default (baseUrl: string): Endpoint> => - new EndpointBuilder>(LOCAL_NEWS_ENDPOINT_NAME) +export default (baseUrl: string): Endpoint => + new EndpointBuilder(LOCAL_NEWS_ENDPOINT_NAME) .withParamsToUrlMapper( (params: ParamsType): string => `${baseUrl}/api/${API_VERSION}/${params.city}/${params.language}/fcm/?channel=news`, ) - .withMapper( - (json: Array): Array => - json.map( - (localNews: JsonLocalNewsType) => - new LocalNewsModel({ - id: localNews.id, - timestamp: DateTime.fromISO(localNews.timestamp), - title: localNews.title, - content: localNews.message, - availableLanguages: mapNewsAvailableLanguages(localNews.available_languages), - }), - ), + .withMapper((json: JsonLocalNewsType[]): LocalNewsModel[] => + json.map( + (localNews: JsonLocalNewsType) => + new LocalNewsModel({ + id: localNews.id, + timestamp: DateTime.fromISO(localNews.timestamp), + title: localNews.title, + content: localNews.message, + availableLanguages: mapNewsAvailableLanguages(localNews.available_languages), + }), + ), ) .build() diff --git a/shared/api/endpoints/createPOIsEndpoint.ts b/shared/api/endpoints/createPOIsEndpoint.ts index cafcf08376..d42fa5bd76 100644 --- a/shared/api/endpoints/createPOIsEndpoint.ts +++ b/shared/api/endpoints/createPOIsEndpoint.ts @@ -15,49 +15,48 @@ type ParamsType = { city: string language: string } -export default (baseUrl: string): Endpoint> => - new EndpointBuilder>(POIS_ENDPOINT_NAME) +export default (baseUrl: string): Endpoint => + new EndpointBuilder(POIS_ENDPOINT_NAME) .withParamsToUrlMapper( (params: ParamsType): string => `${baseUrl}/api/${API_VERSION}/${params.city}/${params.language}/locations/?on_map=1`, ) - .withMapper( - (json: Array): Array => - json.map( - poi => - new PoiModel({ - path: poi.path, - title: poi.title, - content: poi.content, - thumbnail: poi.thumbnail, - availableLanguages: mapAvailableLanguages(poi.available_languages), - excerpt: poi.excerpt, - metaDescription: poi.meta_description ? poi.meta_description : null, - website: poi.website, - phoneNumber: poi.phone_number, - email: poi.email, - temporarilyClosed: poi.temporarily_closed, - openingHours: poi.opening_hours?.map(openingHour => new OpeningHoursModel(openingHour)) ?? null, - appointmentUrl: poi.appointment_url, - category: new PoiCategoryModel({ - id: poi.category.id, - name: poi.category.name, - color: poi.category.color, - iconName: poi.category.icon, - icon: poi.category.icon_url, - }), - location: new LocationModel({ - id: poi.location.id, - name: poi.location.name, - address: poi.location.address, - town: poi.location.town, - postcode: poi.location.postcode, - country: poi.location.country, - latitude: poi.location.latitude, - longitude: poi.location.longitude, - }), - lastUpdate: DateTime.fromISO(poi.last_updated), + .withMapper((json: JsonPoiType[]): PoiModel[] => + json.map( + poi => + new PoiModel({ + path: poi.path, + title: poi.title, + content: poi.content, + thumbnail: poi.thumbnail, + availableLanguages: mapAvailableLanguages(poi.available_languages), + excerpt: poi.excerpt, + metaDescription: poi.meta_description ? poi.meta_description : null, + website: poi.website, + phoneNumber: poi.phone_number, + email: poi.email, + temporarilyClosed: poi.temporarily_closed, + openingHours: poi.opening_hours?.map(openingHour => new OpeningHoursModel(openingHour)) ?? null, + appointmentUrl: poi.appointment_url, + category: new PoiCategoryModel({ + id: poi.category.id, + name: poi.category.name, + color: poi.category.color, + iconName: poi.category.icon, + icon: poi.category.icon_url, }), - ), + location: new LocationModel({ + id: poi.location.id, + name: poi.location.name, + address: poi.location.address, + town: poi.location.town, + postcode: poi.location.postcode, + country: poi.location.country, + latitude: poi.location.latitude, + longitude: poi.location.longitude, + }), + lastUpdate: DateTime.fromISO(poi.last_updated), + }), + ), ) .build() diff --git a/shared/api/endpoints/createSprungbrettJobsEndpoint.ts b/shared/api/endpoints/createSprungbrettJobsEndpoint.ts index c016cf64a1..a53603b30e 100644 --- a/shared/api/endpoints/createSprungbrettJobsEndpoint.ts +++ b/shared/api/endpoints/createSprungbrettJobsEndpoint.ts @@ -5,21 +5,20 @@ import { JsonSprungbrettJobType } from '../types' export const SPRUNGBRETT_JOBS_ENDPOINT_NAME = 'sprungbrettJobs' -export default (baseUrl: string): Endpoint> => - new EndpointBuilder>(SPRUNGBRETT_JOBS_ENDPOINT_NAME) +export default (baseUrl: string): Endpoint => + new EndpointBuilder(SPRUNGBRETT_JOBS_ENDPOINT_NAME) .withParamsToUrlMapper(() => baseUrl) - .withMapper( - (json: { results: Array }): Array => - json.results.map( - (job, index) => - new SprungbrettJobModel({ - id: index, - title: job.title, - location: `${job.zip} ${job.city}`, - url: job.url, - isEmployment: job.employment === '1', - isApprenticeship: job.apprenticeship === '1', - }), - ), + .withMapper((json: { results: JsonSprungbrettJobType[] }): SprungbrettJobModel[] => + json.results.map( + (job, index) => + new SprungbrettJobModel({ + id: index, + title: job.title, + location: `${job.zip} ${job.city}`, + url: job.url, + isEmployment: job.employment === '1', + isApprenticeship: job.apprenticeship === '1', + }), + ), ) .build() diff --git a/shared/api/endpoints/createTunewsElementEndpoint.ts b/shared/api/endpoints/createTunewsElementEndpoint.ts index de56282ade..3faaf0183c 100644 --- a/shared/api/endpoints/createTunewsElementEndpoint.ts +++ b/shared/api/endpoints/createTunewsElementEndpoint.ts @@ -16,7 +16,7 @@ type ParamsType = { export default (baseUrl: string): Endpoint => new EndpointBuilder(TUNEWS_ELEMENT_ENDPOINT_NAME) .withParamsToUrlMapper((params: ParamsType): string => `${baseUrl}/v1/news/${params.id}`) - .withMapper((json: JsonTunewsType | Array, params: ParamsType): TunewsModel => { + .withMapper((json: JsonTunewsType | void[], params: ParamsType): TunewsModel => { // The api is not good and returns an empty array if the tunews does not exist if (Array.isArray(json)) { throw new NotFoundError({ diff --git a/shared/api/endpoints/createTunewsEndpoint.ts b/shared/api/endpoints/createTunewsEndpoint.ts index aed043ac00..057837e682 100644 --- a/shared/api/endpoints/createTunewsEndpoint.ts +++ b/shared/api/endpoints/createTunewsEndpoint.ts @@ -12,23 +12,22 @@ type ParamsType = { page: number count: number } -export default (baseUrl: string): Endpoint> => - new EndpointBuilder>(TUNEWS_ENDPOINT_NAME) +export default (baseUrl: string): Endpoint => + new EndpointBuilder(TUNEWS_ENDPOINT_NAME) .withParamsToUrlMapper( (params: ParamsType): string => `${baseUrl}/v1/news/${params.language}?page=${params.page}&count=${params.count}`, ) - .withMapper( - (json: Array): Array => - json.map( - (tunews: JsonTunewsType) => - new TunewsModel({ - id: tunews.id, - title: tunews.title, - tags: tunews.tags, - date: DateTime.fromJSDate(new Date(tunews.date)), - content: parseHTML(tunews.content), - eNewsNo: tunews.enewsno, - }), - ), + .withMapper((json: JsonTunewsType[]): TunewsModel[] => + json.map( + (tunews: JsonTunewsType) => + new TunewsModel({ + id: tunews.id, + title: tunews.title, + tags: tunews.tags, + date: DateTime.fromJSDate(new Date(tunews.date)), + content: parseHTML(tunews.content), + eNewsNo: tunews.enewsno, + }), + ), ) .build() diff --git a/shared/api/endpoints/createTunewsLanguagesEndpoint.ts b/shared/api/endpoints/createTunewsLanguagesEndpoint.ts index 758f0f9f58..fa70584ae0 100644 --- a/shared/api/endpoints/createTunewsLanguagesEndpoint.ts +++ b/shared/api/endpoints/createTunewsLanguagesEndpoint.ts @@ -5,10 +5,10 @@ import { JsonTunewsLanguageType } from '../types' export const TUNEWS_LANGUAGES_ENDPOINT_NAME = 'tunewsLanguages' -export default (baseUrl: string): Endpoint> => - new EndpointBuilder>(TUNEWS_LANGUAGES_ENDPOINT_NAME) +export default (baseUrl: string): Endpoint => + new EndpointBuilder(TUNEWS_LANGUAGES_ENDPOINT_NAME) .withParamsToUrlMapper(() => `${baseUrl}/v1/news/languages`) - .withMapper((json: Array) => + .withMapper((json: JsonTunewsLanguageType[]) => json .map((language: JsonTunewsLanguageType) => new LanguageModel(language.code, language.name)) .sort((lang1, lang2) => lang1.code.localeCompare(lang2.code)), diff --git a/shared/api/endpoints/testing/CategoriesMapModelBuilder.ts b/shared/api/endpoints/testing/CategoriesMapModelBuilder.ts index 65bedea698..843292edf3 100644 --- a/shared/api/endpoints/testing/CategoriesMapModelBuilder.ts +++ b/shared/api/endpoints/testing/CategoriesMapModelBuilder.ts @@ -27,7 +27,7 @@ class CategoriesMapModelBuilder { _arity: number _city: string _language: string - _categories: Array = [] + _categories: CategoryModel[] = [] _resourceCache: Record = {} _id = 0 diff --git a/shared/api/endpoints/testing/CityModelBuilder.ts b/shared/api/endpoints/testing/CityModelBuilder.ts index 9fe64f60d9..7116494dc2 100644 --- a/shared/api/endpoints/testing/CityModelBuilder.ts +++ b/shared/api/endpoints/testing/CityModelBuilder.ts @@ -128,7 +128,7 @@ class CityModelBuilder { } } - build(): Array { + build(): CityModel[] { return cities.slice(0, this._citiesCount) } } diff --git a/shared/api/endpoints/testing/EventModelBuilder.ts b/shared/api/endpoints/testing/EventModelBuilder.ts index b3e1111f58..20b27fa70e 100644 --- a/shared/api/endpoints/testing/EventModelBuilder.ts +++ b/shared/api/endpoints/testing/EventModelBuilder.ts @@ -35,7 +35,7 @@ class EventModelBuilder { return seedrandom(index + this._seed)() * max } - build(): Array { + build(): EventModel[] { return this.buildAll().map(all => all.event) } diff --git a/shared/api/endpoints/testing/LanguageModelBuilder.ts b/shared/api/endpoints/testing/LanguageModelBuilder.ts index 0f57ffb130..8ce22a0774 100644 --- a/shared/api/endpoints/testing/LanguageModelBuilder.ts +++ b/shared/api/endpoints/testing/LanguageModelBuilder.ts @@ -17,7 +17,7 @@ class LanguageModelBuilder { } } - build(): Array { + build(): LanguageModel[] { return languages.slice(0, this._languagesCount) } } diff --git a/shared/api/endpoints/testing/NewsModelBuilder.ts b/shared/api/endpoints/testing/NewsModelBuilder.ts index e9f0cef57c..8d3f5e9d68 100644 --- a/shared/api/endpoints/testing/NewsModelBuilder.ts +++ b/shared/api/endpoints/testing/NewsModelBuilder.ts @@ -15,17 +15,17 @@ class LocalNewsModelBuilder { this._language = language } - build(): Array { + build(): LocalNewsModel[] { return this.buildAll().map(all => all.newsItem) } /** * Builds the requested amount of news. Two builds with an identical seed will yield equal news. */ - buildAll(): Array<{ + buildAll(): { path: string | null | undefined newsItem: LocalNewsModel - }> { + }[] { return Array.from( { length: this._newsCount, diff --git a/shared/api/endpoints/testing/PoiModelBuilder.ts b/shared/api/endpoints/testing/PoiModelBuilder.ts index 54c8955bf1..dc9386bea0 100644 --- a/shared/api/endpoints/testing/PoiModelBuilder.ts +++ b/shared/api/endpoints/testing/PoiModelBuilder.ts @@ -141,7 +141,7 @@ class PoiModelBuilder { } } - build(): Array { + build(): PoiModel[] { return pois.slice(0, this._poisCount) } } diff --git a/shared/api/models/CategoriesMapModel.ts b/shared/api/models/CategoriesMapModel.ts index 1617a2d726..62c832c1fe 100644 --- a/shared/api/models/CategoriesMapModel.ts +++ b/shared/api/models/CategoriesMapModel.ts @@ -13,14 +13,14 @@ class CategoriesMapModel { * whose parent attributes are first changed from id to path * @param categories CategoryModel as array */ - constructor(categories: Array) { + constructor(categories: CategoryModel[]) { this._categories = new Map(categories.map(category => [category.path, category])) } /** * @return {CategoryModel[]} categories The categories as array */ - toArray(): Array { + toArray(): CategoryModel[] { return Array.from(this._categories.values()) } @@ -38,7 +38,7 @@ class CategoriesMapModel { * @param category The category * @return {CategoryModel[]} The children */ - getChildren(category: CategoryModel): Array { + getChildren(category: CategoryModel): CategoryModel[] { return this.toArray() .filter(_category => _category.parentPath === category.path) .sort((category1, category2) => category1.order - category2.order) @@ -49,8 +49,8 @@ class CategoriesMapModel { * @param category The category * @return {CategoryModel[]} The parents, with the immediate parent last */ - getAncestors(category: CategoryModel): Array { - const parents: Array = [] + getAncestors(category: CategoryModel): CategoryModel[] { + const parents: CategoryModel[] = [] let currentCategory = category while (!currentCategory.isRoot()) { diff --git a/shared/api/models/CityModel.ts b/shared/api/models/CityModel.ts index 694c6a0312..8c4174c823 100644 --- a/shared/api/models/CityModel.ts +++ b/shared/api/models/CityModel.ts @@ -121,7 +121,7 @@ class CityModel { return this._aliases } - static findCityName(cities: ReadonlyArray, code: string): string { + static findCityName(cities: readonly CityModel[], code: string): string { const city = cities.find(city => city.code === code) return city ? city.name : code } diff --git a/shared/api/models/TunewsModel.ts b/shared/api/models/TunewsModel.ts index bf3b4b1a1f..d42a5f1a0c 100644 --- a/shared/api/models/TunewsModel.ts +++ b/shared/api/models/TunewsModel.ts @@ -4,19 +4,12 @@ import { DateTime } from 'luxon' class TunewsModel { _id: number _title: string - _tags: Array + _tags: string[] _date: DateTime _content: string _eNewsNo: string - constructor(params: { - id: number - title: string - date: DateTime - tags: Array - content: string - eNewsNo: string - }) { + constructor(params: { id: number; title: string; date: DateTime; tags: string[]; content: string; eNewsNo: string }) { const { id, date, title, tags, content, eNewsNo } = params this._id = id this._title = decodeHTML(title) @@ -38,7 +31,7 @@ class TunewsModel { return this._date } - get tags(): Array { + get tags(): string[] { return this._tags } diff --git a/shared/api/types.ts b/shared/api/types.ts index a6e5193f7d..605e5054f4 100644 --- a/shared/api/types.ts +++ b/shared/api/types.ts @@ -121,7 +121,7 @@ export type JsonEventType = { export type JsonTunewsType = { id: number title: string - tags: Array + tags: string[] date: string content: string enewsno: string diff --git a/shared/routes/InternalPathnameParser.ts b/shared/routes/InternalPathnameParser.ts index ffe2dab6a4..84253e36b6 100644 --- a/shared/routes/InternalPathnameParser.ts +++ b/shared/routes/InternalPathnameParser.ts @@ -20,7 +20,7 @@ import { parseQueryParams } from './query' const ENTITY_ID_INDEX = 3 class InternalPathnameParser { - _parts: Array + _parts: string[] _length: number _fallbackLanguageCode: string _fixedCity: string | null diff --git a/shared/routes/pathname.ts b/shared/routes/pathname.ts index ffca183e1d..0c67f0668c 100644 --- a/shared/routes/pathname.ts +++ b/shared/routes/pathname.ts @@ -20,7 +20,7 @@ type CityContentRouteUrlType = { path?: string | null | undefined } -const constructPathname = (parts: Array) => { +const constructPathname = (parts: (string | null | undefined)[]) => { const pathname = parts .filter(Boolean) .map(part => part?.toLowerCase()) diff --git a/tools/yarn.lock b/tools/yarn.lock index 53259e91d6..c656fca106 100644 --- a/tools/yarn.lock +++ b/tools/yarn.lock @@ -136,40 +136,37 @@ universal-github-app-jwt "^2.2.0" universal-user-agent "^7.0.0" -"@octokit/auth-oauth-app@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-app/-/auth-oauth-app-7.1.0.tgz#d0f74e19ebd5a4829cb780c107cedd6c894f20fc" - integrity sha512-w+SyJN/b0l/HEb4EOPRudo7uUOSW51jcK1jwLa+4r7PA8FPFpoxEnHBHMITqCsc/3Vo2qqFjgQfz/xUUvsSQnA== +"@octokit/auth-oauth-app@^8.1.0": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz#6204affa6e86f535016799cadf2af9befe5e893c" + integrity sha512-5UtmxXAvU2wfcHIPPDWzVSAWXVJzG3NWsxb7zCFplCWEmMCArSZV0UQu5jw5goLQXbFyOr5onzEH37UJB3zQQg== dependencies: - "@octokit/auth-oauth-device" "^6.1.0" - "@octokit/auth-oauth-user" "^4.1.0" - "@octokit/request" "^8.3.1" + "@octokit/auth-oauth-device" "^7.0.0" + "@octokit/auth-oauth-user" "^5.0.1" + "@octokit/request" "^9.0.0" "@octokit/types" "^13.0.0" - "@types/btoa-lite" "^1.0.0" - btoa-lite "^1.0.0" - universal-user-agent "^6.0.0" - -"@octokit/auth-oauth-device@^6.1.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-device/-/auth-oauth-device-6.1.0.tgz#f868213a3db05fe27e68d1fc607502a322379dd9" - integrity sha512-FNQ7cb8kASufd6Ej4gnJ3f1QB5vJitkoV1O0/g6e6lUsQ7+VsSNRHRmFScN2tV4IgKA12frrr/cegUs0t+0/Lw== + universal-user-agent "^7.0.0" + +"@octokit/auth-oauth-device@^7.0.0", "@octokit/auth-oauth-device@^7.0.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.1.tgz#7b4f8f97cbcadbe9894d48cde4406dbdef39875a" + integrity sha512-HWl8lYueHonuyjrKKIup/1tiy0xcmQCdq5ikvMO1YwkNNkxb6DXfrPjrMYItNLyCP/o2H87WuijuE+SlBTT8eg== dependencies: - "@octokit/oauth-methods" "^4.1.0" - "@octokit/request" "^8.3.1" + "@octokit/oauth-methods" "^5.0.0" + "@octokit/request" "^9.0.0" "@octokit/types" "^13.0.0" - universal-user-agent "^6.0.0" + universal-user-agent "^7.0.0" -"@octokit/auth-oauth-user@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-user/-/auth-oauth-user-4.1.0.tgz#32e5529f8bd961af9839a1f8c6ab0c8ad2184eee" - integrity sha512-FrEp8mtFuS/BrJyjpur+4GARteUCrPeR/tZJzD8YourzoVhRics7u7we/aDcKv+yywRNwNi/P4fRi631rG/OyQ== +"@octokit/auth-oauth-user@^5.0.1", "@octokit/auth-oauth-user@^5.1.0": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.1.tgz#4f1570c6ee15bb9ddc3dcca83308dcaa159e3848" + integrity sha512-rRkMz0ErOppdvEfnemHJXgZ9vTPhBuC6yASeFaB7I2yLMd7QpjfrL1mnvRPlyKo+M6eeLxrKanXJ9Qte29SRsw== dependencies: - "@octokit/auth-oauth-device" "^6.1.0" - "@octokit/oauth-methods" "^4.1.0" - "@octokit/request" "^8.3.1" + "@octokit/auth-oauth-device" "^7.0.1" + "@octokit/oauth-methods" "^5.0.0" + "@octokit/request" "^9.0.1" "@octokit/types" "^13.0.0" - btoa-lite "^1.0.0" - universal-user-agent "^6.0.0" + universal-user-agent "^7.0.0" "@octokit/auth-token@^5.0.0": version "5.1.1" @@ -197,14 +194,6 @@ "@octokit/types" "^13.0.0" universal-user-agent "^7.0.2" -"@octokit/endpoint@^9.0.1": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.5.tgz#e6c0ee684e307614c02fc6ac12274c50da465c44" - integrity sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw== - dependencies: - "@octokit/types" "^13.1.0" - universal-user-agent "^6.0.0" - "@octokit/graphql@^8.0.0": version "8.1.1" resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-8.1.1.tgz#3cacab5f2e55d91c733e3bf481d3a3f8a5f639c4" @@ -214,21 +203,20 @@ "@octokit/types" "^13.0.0" universal-user-agent "^7.0.0" -"@octokit/oauth-authorization-url@^6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-6.0.2.tgz#cc82ca29cc5e339c9921672f39f2b3f5c8eb6ef2" - integrity sha512-CdoJukjXXxqLNK4y/VOiVzQVjibqoj/xHgInekviUJV73y/BSIcwvJ/4aNHPBPKcPWFnd4/lO9uqRV65jXhcLA== +"@octokit/oauth-authorization-url@^7.0.0": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz#0e17c2225eb66b58ec902d02b6f1315ffe9ff04b" + integrity sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA== -"@octokit/oauth-methods@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@octokit/oauth-methods/-/oauth-methods-4.1.0.tgz#1403ac9c4d4e277922fddc4c89fa8a782f8f791b" - integrity sha512-4tuKnCRecJ6CG6gr0XcEXdZtkTDbfbnD5oaHBmLERTjTMZNi2CbfEHZxPU41xXLDG4DfKf+sonu00zvKI9NSbw== +"@octokit/oauth-methods@^5.0.0": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@octokit/oauth-methods/-/oauth-methods-5.1.2.tgz#fd31d2a69f4c91d1abc1ed1814dda5252c697e02" + integrity sha512-C5lglRD+sBlbrhCUTxgJAFjWgJlmTx5bQ7Ch0+2uqRjYv7Cfb5xpX4WuSC9UgQna3sqRGBL9EImX9PvTpMaQ7g== dependencies: - "@octokit/oauth-authorization-url" "^6.0.2" - "@octokit/request" "^8.3.1" - "@octokit/request-error" "^5.1.0" + "@octokit/oauth-authorization-url" "^7.0.0" + "@octokit/request" "^9.1.0" + "@octokit/request-error" "^6.1.0" "@octokit/types" "^13.0.0" - btoa-lite "^1.0.0" "@octokit/openapi-types@^22.1.0": version "22.1.0" @@ -259,15 +247,6 @@ dependencies: "@octokit/types" "^13.5.0" -"@octokit/request-error@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.1.0.tgz#ee4138538d08c81a60be3f320cd71063064a3b30" - integrity sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q== - dependencies: - "@octokit/types" "^13.1.0" - deprecation "^2.0.0" - once "^1.4.0" - "@octokit/request-error@^6.0.1": version "6.1.4" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.4.tgz#ad96e29148d19edc2ba8009fc2b5a24a36c90f16" @@ -275,17 +254,14 @@ dependencies: "@octokit/types" "^13.0.0" -"@octokit/request@^8.3.1": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.4.0.tgz#7f4b7b1daa3d1f48c0977ad8fffa2c18adef8974" - integrity sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw== +"@octokit/request-error@^6.1.0", "@octokit/request-error@^6.1.1": + version "6.1.5" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.5.tgz#907099e341c4e6179db623a0328d678024f54653" + integrity sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ== dependencies: - "@octokit/endpoint" "^9.0.1" - "@octokit/request-error" "^5.1.0" - "@octokit/types" "^13.1.0" - universal-user-agent "^6.0.0" + "@octokit/types" "^13.0.0" -"@octokit/request@^9.0.0": +"@octokit/request@^9.0.0", "@octokit/request@^9.0.1", "@octokit/request@^9.1.0", "@octokit/request@^9.1.1": version "9.1.3" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-9.1.3.tgz#42b693bc06238f43af3c037ebfd35621c6457838" integrity sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA== @@ -312,6 +288,13 @@ dependencies: "@octokit/openapi-types" "^22.1.0" +"@octokit/types@^13.4.1": + version "13.6.1" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.6.1.tgz#432fc6c0aaae54318e5b2d3e15c22ac97fc9b15f" + integrity sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g== + dependencies: + "@octokit/openapi-types" "^22.2.0" + "@octokit/types@^13.5.0": version "13.5.0" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.5.0.tgz#4796e56b7b267ebc7c921dcec262b3d5bfb18883" @@ -319,23 +302,11 @@ dependencies: "@octokit/openapi-types" "^22.2.0" -"@types/btoa-lite@^1.0.0": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@types/btoa-lite/-/btoa-lite-1.0.2.tgz#82bb6aab00abf7cff3ca2825abe010c0cd536ae5" - integrity sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg== - "@types/js-yaml@^4.0.9": version "4.0.9" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg== -"@types/jsonwebtoken@^9.0.0": - version "9.0.6" - resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz#d1af3544d99ad992fb6681bbe60676e06b032bd3" - integrity sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw== - dependencies: - "@types/node" "*" - "@types/node-fetch@^2.6.11": version "2.6.11" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" @@ -371,16 +342,6 @@ before-after-hook@^3.0.2: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-3.0.2.tgz#d5665a5fa8b62294a5aa0a499f933f4a1016195d" integrity sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A== -btoa-lite@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" - integrity sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA== - -buffer-equal-constant-time@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" - integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== - combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -403,18 +364,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -deprecation@^2.0.0, deprecation@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== - -ecdsa-sig-formatter@1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" - integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== - dependencies: - safe-buffer "^5.0.1" - esbuild@~0.23.0: version "0.23.1" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.1.tgz#40fdc3f9265ec0beae6f59824ade1bd3d3d2dab8" @@ -488,74 +437,6 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsonwebtoken@^9.0.2: - version "9.0.2" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" - integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== - dependencies: - jws "^3.2.2" - lodash.includes "^4.3.0" - lodash.isboolean "^3.0.3" - lodash.isinteger "^4.0.4" - lodash.isnumber "^3.0.3" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.once "^4.0.0" - ms "^2.1.1" - semver "^7.5.4" - -jwa@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" - integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== - dependencies: - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.11" - safe-buffer "^5.0.1" - -jws@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" - integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== - dependencies: - jwa "^1.4.1" - safe-buffer "^5.0.1" - -lodash.includes@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" - integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== - -lodash.isboolean@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" - integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== - -lodash.isinteger@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" - integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== - -lodash.isnumber@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" - integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== - -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== - -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== - -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== - lru-cache@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" @@ -573,11 +454,6 @@ mime-types@^2.1.12: dependencies: mime-db "1.51.0" -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - node-domexception@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" @@ -592,28 +468,11 @@ node-fetch@^3.3.2: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" -once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - resolve-pkg-maps@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -safe-buffer@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -semver@^7.5.4: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - tsx@^4.8.2: version "4.19.0" resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.19.0.tgz#6166cb399b17d14d125e6158d23384045cfdf4f6" @@ -634,18 +493,10 @@ undici-types@~6.19.2: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== -universal-github-app-jwt@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-1.1.2.tgz#8c1867a394d7d9d42cda34f11d1bcb023797d8df" - integrity sha512-t1iB2FmLFE+yyJY9+3wMx0ejB+MQpEVkH0gQv7dR6FZyltyq+ZZO0uDpbopxhrZ3SLEO4dCEkIujOMldEQ2iOA== - dependencies: - "@types/jsonwebtoken" "^9.0.0" - jsonwebtoken "^9.0.2" - -universal-user-agent@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" - integrity sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ== +universal-github-app-jwt@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-2.2.0.tgz#dc6c8929e76f1996a766ba2a08fb420f73365d77" + integrity sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ== universal-user-agent@^7.0.0, universal-user-agent@^7.0.2: version "7.0.2" @@ -656,8 +507,3 @@ web-streams-polyfill@^3.0.3: version "3.2.1" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== diff --git a/web/src/components/Breadcrumbs.tsx b/web/src/components/Breadcrumbs.tsx index 33781a3aca..0b0d42f48e 100644 --- a/web/src/components/Breadcrumbs.tsx +++ b/web/src/components/Breadcrumbs.tsx @@ -48,7 +48,7 @@ const StyledLink = styled(Link)` ` type BreadcrumbsProps = { - ancestorBreadcrumbs: Array + ancestorBreadcrumbs: BreadcrumbModel[] currentBreadcrumb: BreadcrumbModel } diff --git a/web/src/components/CityContentHeader.tsx b/web/src/components/CityContentHeader.tsx index 66d3eca111..6f2903cd32 100644 --- a/web/src/components/CityContentHeader.tsx +++ b/web/src/components/CityContentHeader.tsx @@ -27,7 +27,7 @@ type CityContentHeaderProps = { cityModel: CityModel route: RouteType languageCode: string - languageChangePaths: Array<{ code: string; path: string | null; name: string }> | null + languageChangePaths: { code: string; path: string | null; name: string }[] | null } const CityContentHeader = ({ @@ -80,7 +80,7 @@ const CityContentHeader = ({ />, ] - const getNavigationItems = (): Array => { + const getNavigationItems = (): ReactElement[] => { const isNewsVisible = buildConfig().featureFlags.newsStream && (localNewsEnabled || tunewsEnabled) const isEventsVisible = eventsEnabled const isPoisVisible = buildConfig().featureFlags.pois && poisEnabled @@ -90,7 +90,7 @@ const CityContentHeader = ({ return [] } - const items: Array = [ + const items: ReactElement[] = [ | null + languageChangePaths: { code: string; path: string | null; name: string }[] | null isLoading: boolean city: CityModel languageCode: string diff --git a/web/src/components/CitySelector.tsx b/web/src/components/CitySelector.tsx index f333b21bc5..bfb75f9394 100644 --- a/web/src/components/CitySelector.tsx +++ b/web/src/components/CitySelector.tsx @@ -27,7 +27,7 @@ const CityListParent = styled.div<{ $stickyTop: number }>` ` type CitySelectorProps = { - cities: Array + cities: CityModel[] language: string } diff --git a/web/src/components/Footer.tsx b/web/src/components/Footer.tsx index a8fde7d5db..1a548bd57a 100644 --- a/web/src/components/Footer.tsx +++ b/web/src/components/Footer.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components' import buildConfig from '../constants/buildConfig' type FooterProps = { - children: Array | ReactNode + children: ReactNode[] | ReactNode overlay?: boolean } diff --git a/web/src/components/Header.tsx b/web/src/components/Header.tsx index d1dd6608bf..630a8f5ca8 100644 --- a/web/src/components/Header.tsx +++ b/web/src/components/Header.tsx @@ -12,9 +12,9 @@ import KebabMenu from './KebabMenu' import NavigationBarScrollContainer from './NavigationBarScrollContainer' type HeaderProps = { - navigationItems: Array> - actionItems: Array - kebabItems: Array + navigationItems: ReactElement[] + actionItems: ReactNode[] + kebabItems: ReactNode[] logoHref: string cityName?: string cityCode?: string diff --git a/web/src/components/HeaderLanguageSelectorItem.tsx b/web/src/components/HeaderLanguageSelectorItem.tsx index 83cf215125..4d191297a6 100644 --- a/web/src/components/HeaderLanguageSelectorItem.tsx +++ b/web/src/components/HeaderLanguageSelectorItem.tsx @@ -9,7 +9,7 @@ import KebabActionItemDropDown from './KebabActionItemDropDown' import Selector from './Selector' type HeaderLanguageSelectorItemProps = { - selectorItems: Array + selectorItems: SelectorItemModel[] activeItemCode: string inKebabMenu?: boolean closeSidebar?: () => void diff --git a/web/src/components/Helmet.tsx b/web/src/components/Helmet.tsx index 12a1ebda7f..3ee63116e3 100644 --- a/web/src/components/Helmet.tsx +++ b/web/src/components/Helmet.tsx @@ -8,7 +8,7 @@ import buildConfig from '../constants/buildConfig' type HelmetProps = { pageTitle: string metaDescription?: string | null - languageChangePaths?: Array<{ code: string; path: string | null; name: string }> + languageChangePaths?: { code: string; path: string | null; name: string }[] rootPage?: boolean cityModel?: CityModel } diff --git a/web/src/components/JsonLdBreadcrumbs.tsx b/web/src/components/JsonLdBreadcrumbs.tsx index d1b365309d..28668fedc8 100644 --- a/web/src/components/JsonLdBreadcrumbs.tsx +++ b/web/src/components/JsonLdBreadcrumbs.tsx @@ -5,7 +5,7 @@ import { BreadcrumbList, WithContext } from 'schema-dts' import BreadcrumbModel from '../models/BreadcrumbModel' import { urlFromPath } from '../utils/stringUtils' -export const createJsonLd = (breadcrumbs: Array): WithContext => +export const createJsonLd = (breadcrumbs: BreadcrumbModel[]): WithContext => // https://developers.google.com/search/docs/data-types/breadcrumb ({ '@context': 'https://schema.org', @@ -19,7 +19,7 @@ export const createJsonLd = (breadcrumbs: Array): WithContext + breadcrumbs: BreadcrumbModel[] } const JsonLdBreadcrumbs = ({ breadcrumbs }: JsonLdBreadcrumbsProps): ReactElement => ( diff --git a/web/src/components/KebabMenu.tsx b/web/src/components/KebabMenu.tsx index fab9e5a5f3..360f2426ff 100644 --- a/web/src/components/KebabMenu.tsx +++ b/web/src/components/KebabMenu.tsx @@ -11,7 +11,7 @@ import Button from './base/Button' import Icon from './base/Icon' type KebabMenuProps = { - items: Array + items: ReactNode[] show: boolean setShow: (show: boolean) => void Footer: ReactNode diff --git a/web/src/components/LanguageFailure.tsx b/web/src/components/LanguageFailure.tsx index 71db17862f..1d8cfae8c1 100644 --- a/web/src/components/LanguageFailure.tsx +++ b/web/src/components/LanguageFailure.tsx @@ -15,7 +15,7 @@ const ChooseLanguage = styled.p` type LanguageFailureProps = { cityModel: CityModel languageCode: string - languageChangePaths: Array<{ code: string; path: string | null; name: string }> + languageChangePaths: { code: string; path: string | null; name: string }[] } const LanguageFailure = ({ cityModel, languageCode, languageChangePaths }: LanguageFailureProps): ReactElement => { diff --git a/web/src/components/LanguageSelector.tsx b/web/src/components/LanguageSelector.tsx index 51e2e9e906..3b9c78052c 100644 --- a/web/src/components/LanguageSelector.tsx +++ b/web/src/components/LanguageSelector.tsx @@ -8,7 +8,7 @@ import HeaderLanguageSelectorItem from './HeaderLanguageSelectorItem' type LanguageSelectorProps = { languageCode: string isHeaderActionItem: boolean - languageChangePaths: Array<{ code: string; path: string | null; name: string }> | null + languageChangePaths: { code: string; path: string | null; name: string }[] | null inKebabMenu?: boolean closeSidebar?: () => void } diff --git a/web/src/components/List.tsx b/web/src/components/List.tsx index 78237a361e..51ba08a9a0 100644 --- a/web/src/components/List.tsx +++ b/web/src/components/List.tsx @@ -11,7 +11,7 @@ const NoItemsMessage = styled.div` ` type ListProps = { - items: Array + items: T[] noItemsMessage: string renderItem: (item: T) => ReactNode borderless?: boolean diff --git a/web/src/components/LocalNewsList.tsx b/web/src/components/LocalNewsList.tsx index 3eddae65f9..1d9cedd9a5 100644 --- a/web/src/components/LocalNewsList.tsx +++ b/web/src/components/LocalNewsList.tsx @@ -17,7 +17,7 @@ const Wrapper = styled.div` ` type LocalNewsListProps = { - items: Array + items: LocalNewsModel[] noItemsMessage: string renderItem: (item: LocalNewsModel, city: string) => ReactNode city: string diff --git a/web/src/components/Selector.tsx b/web/src/components/Selector.tsx index 318822d07d..3b45961887 100644 --- a/web/src/components/Selector.tsx +++ b/web/src/components/Selector.tsx @@ -72,7 +72,7 @@ const Wrapper = styled.div<{ $vertical: boolean }>` type SelectorProps = { verticalLayout: boolean closeDropDown?: () => void - items: Array + items: SelectorItemModel[] activeItemCode?: string disabledItemTooltip: string } diff --git a/web/src/components/Tiles.tsx b/web/src/components/Tiles.tsx index f066774b25..4886cf5364 100644 --- a/web/src/components/Tiles.tsx +++ b/web/src/components/Tiles.tsx @@ -23,7 +23,7 @@ const TilesRow = styled.div` type TilesProps = { title: string | null - tiles: Array + tiles: TileModel[] } const Tiles = ({ title, tiles }: TilesProps): ReactElement => ( From 050e3c190755256381c4f2583a456d83806840fa Mon Sep 17 00:00:00 2001 From: ztefanie Date: Thu, 24 Oct 2024 11:51:51 +0200 Subject: [PATCH 07/29] 2945: Small adjustments for chatbot and chatperson icons --- .../icons/{chatbot-bot.svg => chat-bot.svg} | 4 ++-- .../{chatbot-person.svg => chat-person.svg} | 4 ++-- web/src/assets/index.ts | 8 ++++---- web/src/components/ChatMessage.tsx | 19 +++++++++---------- web/src/components/base/Icon.tsx | 1 + 5 files changed, 18 insertions(+), 18 deletions(-) rename assets/icons/{chatbot-bot.svg => chat-bot.svg} (96%) rename assets/icons/{chatbot-person.svg => chat-person.svg} (89%) diff --git a/assets/icons/chatbot-bot.svg b/assets/icons/chat-bot.svg similarity index 96% rename from assets/icons/chatbot-bot.svg rename to assets/icons/chat-bot.svg index 31cbd00b2a..d269472545 100644 --- a/assets/icons/chatbot-bot.svg +++ b/assets/icons/chat-bot.svg @@ -1,4 +1,4 @@ - - + + diff --git a/assets/icons/chatbot-person.svg b/assets/icons/chat-person.svg similarity index 89% rename from assets/icons/chatbot-person.svg rename to assets/icons/chat-person.svg index 03fd461865..de09e960a7 100644 --- a/assets/icons/chatbot-person.svg +++ b/assets/icons/chat-person.svg @@ -1,4 +1,4 @@ - - + + diff --git a/web/src/assets/index.ts b/web/src/assets/index.ts index 40c0799d56..e45ff89a45 100644 --- a/web/src/assets/index.ts +++ b/web/src/assets/index.ts @@ -12,9 +12,9 @@ import CalendarTodayRecurringIcon from '../../../assets/icons/calendar-today-rec import CalendarTodayIcon from '../../../assets/icons/calendar-today.svg' import CalendarIcon from '../../../assets/icons/calendar.svg' import CategoriesIcon from '../../../assets/icons/categories.svg' +import ChatBot from '../../../assets/icons/chat-bot.svg' +import ChatPerson from '../../../assets/icons/chat-person.svg' import ChatIcon from '../../../assets/icons/chat.svg' -import ChatbotBot from '../../../assets/icons/chatbot-bot.svg' -import ChatbotPerson from '../../../assets/icons/chatbot-person.svg' import ClockIcon from '../../../assets/icons/clock.svg' import CloseIcon from '../../../assets/icons/close.svg' import CopyIcon from '../../../assets/icons/copy.svg' @@ -68,8 +68,8 @@ export { CalendarTodayIcon, CalendarTodayRecurringIcon, CategoriesIcon, - ChatbotPerson, - ChatbotBot, + ChatPerson, + ChatBot, ChatIcon, ClockIcon, CloseIcon, diff --git a/web/src/components/ChatMessage.tsx b/web/src/components/ChatMessage.tsx index f31dd17073..95656adf86 100644 --- a/web/src/components/ChatMessage.tsx +++ b/web/src/components/ChatMessage.tsx @@ -5,7 +5,7 @@ import styled from 'styled-components' import ChatMessageModel from 'shared/api/models/ChatMessageModel' -import { ChatbotBot, ChatbotPerson } from '../assets' +import { ChatBot, ChatPerson } from '../assets' import buildConfig from '../constants/buildConfig' import RemoteContent from './RemoteContent' import Icon from './base/Icon' @@ -50,20 +50,19 @@ const Circle = styled.div` type ChatMessageProps = { message: ChatMessageModel; showIcon: boolean } +const getIcon = (userIsAuthor: boolean, isAutomaticAnswer: boolean): ReactElement => { + if (userIsAuthor) { + return {t('user')} + } + const icon = isAutomaticAnswer ? ChatBot : ChatPerson + return +} + const ChatMessage = ({ message, showIcon }: ChatMessageProps): ReactElement => { - // TODO 2799 Check if Remote content is really needed here or how external links will be delivered via api const navigate = useNavigate() const { t } = useTranslation('chat') const { body, userIsAuthor, isAutomaticAnswer } = message - const getIcon = (userIsAuthor: boolean, isAutomaticAnswer: boolean): ReactElement => { - if (userIsAuthor) { - return {t('user')} - } - const icon = isAutomaticAnswer ? ChatbotBot : ChatbotPerson - return - } - return ( {getIcon(userIsAuthor, isAutomaticAnswer)} diff --git a/web/src/components/base/Icon.tsx b/web/src/components/base/Icon.tsx index 71d3f1ad9b..5309c52b41 100644 --- a/web/src/components/base/Icon.tsx +++ b/web/src/components/base/Icon.tsx @@ -10,6 +10,7 @@ const StyledIcon = styled(SVG)<{ $directionDependent: boolean; $reverse: boolean color: ${props => props.theme.colors.textColor}; width: 24px; height: 24px; + --theme-color: ${props => props.theme.colors.themeColor}; ` type IconProps = { From fb8dfd9f72e4c6234002eb26882e03ffecb47387 Mon Sep 17 00:00:00 2001 From: Simon Kleinle <80710541+simomps@users.noreply.github.com> Date: Thu, 24 Oct 2024 13:26:54 +0200 Subject: [PATCH 08/29] Revert yarn.lock --- tools/yarn.lock | 233 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 181 insertions(+), 52 deletions(-) diff --git a/tools/yarn.lock b/tools/yarn.lock index c656fca106..48630ccc48 100644 --- a/tools/yarn.lock +++ b/tools/yarn.lock @@ -136,37 +136,39 @@ universal-github-app-jwt "^2.2.0" universal-user-agent "^7.0.0" -"@octokit/auth-oauth-app@^8.1.0": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz#6204affa6e86f535016799cadf2af9befe5e893c" - integrity sha512-5UtmxXAvU2wfcHIPPDWzVSAWXVJzG3NWsxb7zCFplCWEmMCArSZV0UQu5jw5goLQXbFyOr5onzEH37UJB3zQQg== +"@octokit/auth-oauth-app@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-app/-/auth-oauth-app-7.1.0.tgz#d0f74e19ebd5a4829cb780c107cedd6c894f20fc" + integrity sha512-w+SyJN/b0l/HEb4EOPRudo7uUOSW51jcK1jwLa+4r7PA8FPFpoxEnHBHMITqCsc/3Vo2qqFjgQfz/xUUvsSQnA== dependencies: - "@octokit/auth-oauth-device" "^7.0.0" - "@octokit/auth-oauth-user" "^5.0.1" - "@octokit/request" "^9.0.0" + "@octokit/auth-oauth-device" "^6.1.0" + "@octokit/auth-oauth-user" "^4.1.0" + "@octokit/request" "^8.3.1" "@octokit/types" "^13.0.0" - universal-user-agent "^7.0.0" - -"@octokit/auth-oauth-device@^7.0.0", "@octokit/auth-oauth-device@^7.0.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.1.tgz#7b4f8f97cbcadbe9894d48cde4406dbdef39875a" - integrity sha512-HWl8lYueHonuyjrKKIup/1tiy0xcmQCdq5ikvMO1YwkNNkxb6DXfrPjrMYItNLyCP/o2H87WuijuE+SlBTT8eg== + "@types/btoa-lite" "^1.0.0" + btoa-lite "^1.0.0" + universal-user-agent "^6.0.0" +"@octokit/auth-oauth-device@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-device/-/auth-oauth-device-6.1.0.tgz#f868213a3db05fe27e68d1fc607502a322379dd9" + integrity sha512-FNQ7cb8kASufd6Ej4gnJ3f1QB5vJitkoV1O0/g6e6lUsQ7+VsSNRHRmFScN2tV4IgKA12frrr/cegUs0t+0/Lw== dependencies: - "@octokit/oauth-methods" "^5.0.0" - "@octokit/request" "^9.0.0" + "@octokit/oauth-methods" "^4.1.0" + "@octokit/request" "^8.3.1" "@octokit/types" "^13.0.0" - universal-user-agent "^7.0.0" + universal-user-agent "^6.0.0" -"@octokit/auth-oauth-user@^5.0.1", "@octokit/auth-oauth-user@^5.1.0": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.1.tgz#4f1570c6ee15bb9ddc3dcca83308dcaa159e3848" - integrity sha512-rRkMz0ErOppdvEfnemHJXgZ9vTPhBuC6yASeFaB7I2yLMd7QpjfrL1mnvRPlyKo+M6eeLxrKanXJ9Qte29SRsw== +"@octokit/auth-oauth-user@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-user/-/auth-oauth-user-4.1.0.tgz#32e5529f8bd961af9839a1f8c6ab0c8ad2184eee" + integrity sha512-FrEp8mtFuS/BrJyjpur+4GARteUCrPeR/tZJzD8YourzoVhRics7u7we/aDcKv+yywRNwNi/P4fRi631rG/OyQ== dependencies: - "@octokit/auth-oauth-device" "^7.0.1" - "@octokit/oauth-methods" "^5.0.0" - "@octokit/request" "^9.0.1" + "@octokit/auth-oauth-device" "^6.1.0" + "@octokit/oauth-methods" "^4.1.0" + "@octokit/request" "^8.3.1" "@octokit/types" "^13.0.0" - universal-user-agent "^7.0.0" + btoa-lite "^1.0.0" + universal-user-agent "^6.0.0" "@octokit/auth-token@^5.0.0": version "5.1.1" @@ -194,6 +196,13 @@ "@octokit/types" "^13.0.0" universal-user-agent "^7.0.2" +"@octokit/endpoint@^9.0.1": + version "9.0.5" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.5.tgz#e6c0ee684e307614c02fc6ac12274c50da465c44" + integrity sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw== + dependencies: + "@octokit/types" "^13.1.0" + universal-user-agent "^6.0.0" "@octokit/graphql@^8.0.0": version "8.1.1" resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-8.1.1.tgz#3cacab5f2e55d91c733e3bf481d3a3f8a5f639c4" @@ -203,20 +212,21 @@ "@octokit/types" "^13.0.0" universal-user-agent "^7.0.0" -"@octokit/oauth-authorization-url@^7.0.0": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz#0e17c2225eb66b58ec902d02b6f1315ffe9ff04b" - integrity sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA== +"@octokit/oauth-authorization-url@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-6.0.2.tgz#cc82ca29cc5e339c9921672f39f2b3f5c8eb6ef2" + integrity sha512-CdoJukjXXxqLNK4y/VOiVzQVjibqoj/xHgInekviUJV73y/BSIcwvJ/4aNHPBPKcPWFnd4/lO9uqRV65jXhcLA== -"@octokit/oauth-methods@^5.0.0": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@octokit/oauth-methods/-/oauth-methods-5.1.2.tgz#fd31d2a69f4c91d1abc1ed1814dda5252c697e02" - integrity sha512-C5lglRD+sBlbrhCUTxgJAFjWgJlmTx5bQ7Ch0+2uqRjYv7Cfb5xpX4WuSC9UgQna3sqRGBL9EImX9PvTpMaQ7g== +"@octokit/oauth-methods@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@octokit/oauth-methods/-/oauth-methods-4.1.0.tgz#1403ac9c4d4e277922fddc4c89fa8a782f8f791b" + integrity sha512-4tuKnCRecJ6CG6gr0XcEXdZtkTDbfbnD5oaHBmLERTjTMZNi2CbfEHZxPU41xXLDG4DfKf+sonu00zvKI9NSbw== dependencies: - "@octokit/oauth-authorization-url" "^7.0.0" - "@octokit/request" "^9.1.0" - "@octokit/request-error" "^6.1.0" + "@octokit/oauth-authorization-url" "^6.0.2" + "@octokit/request" "^8.3.1" + "@octokit/request-error" "^5.1.0" "@octokit/types" "^13.0.0" + btoa-lite "^1.0.0" "@octokit/openapi-types@^22.1.0": version "22.1.0" @@ -247,6 +257,14 @@ dependencies: "@octokit/types" "^13.5.0" +"@octokit/request-error@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.1.0.tgz#ee4138538d08c81a60be3f320cd71063064a3b30" + integrity sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q== + dependencies: + "@octokit/types" "^13.1.0" + deprecation "^2.0.0" + once "^1.4.0" "@octokit/request-error@^6.0.1": version "6.1.4" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.4.tgz#ad96e29148d19edc2ba8009fc2b5a24a36c90f16" @@ -254,14 +272,17 @@ dependencies: "@octokit/types" "^13.0.0" -"@octokit/request-error@^6.1.0", "@octokit/request-error@^6.1.1": - version "6.1.5" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.5.tgz#907099e341c4e6179db623a0328d678024f54653" - integrity sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ== +"@octokit/request@^8.3.1": + version "8.4.0" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.4.0.tgz#7f4b7b1daa3d1f48c0977ad8fffa2c18adef8974" + integrity sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw== dependencies: - "@octokit/types" "^13.0.0" + "@octokit/endpoint" "^9.0.1" + "@octokit/request-error" "^5.1.0" + "@octokit/types" "^13.1.0" + universal-user-agent "^6.0.0" -"@octokit/request@^9.0.0", "@octokit/request@^9.0.1", "@octokit/request@^9.1.0", "@octokit/request@^9.1.1": +"@octokit/request@^9.0.0": version "9.1.3" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-9.1.3.tgz#42b693bc06238f43af3c037ebfd35621c6457838" integrity sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA== @@ -288,13 +309,6 @@ dependencies: "@octokit/openapi-types" "^22.1.0" -"@octokit/types@^13.4.1": - version "13.6.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.6.1.tgz#432fc6c0aaae54318e5b2d3e15c22ac97fc9b15f" - integrity sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g== - dependencies: - "@octokit/openapi-types" "^22.2.0" - "@octokit/types@^13.5.0": version "13.5.0" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.5.0.tgz#4796e56b7b267ebc7c921dcec262b3d5bfb18883" @@ -302,11 +316,21 @@ dependencies: "@octokit/openapi-types" "^22.2.0" +"@types/btoa-lite@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/btoa-lite/-/btoa-lite-1.0.2.tgz#82bb6aab00abf7cff3ca2825abe010c0cd536ae5" + integrity sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg== "@types/js-yaml@^4.0.9": version "4.0.9" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg== +"@types/jsonwebtoken@^9.0.0": + version "9.0.6" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz#d1af3544d99ad992fb6681bbe60676e06b032bd3" + integrity sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw== + dependencies: + "@types/node" "*" "@types/node-fetch@^2.6.11": version "2.6.11" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" @@ -342,6 +366,14 @@ before-after-hook@^3.0.2: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-3.0.2.tgz#d5665a5fa8b62294a5aa0a499f933f4a1016195d" integrity sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A== +btoa-lite@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" + integrity sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA== +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -364,6 +396,16 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +deprecation@^2.0.0, deprecation@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" esbuild@~0.23.0: version "0.23.1" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.1.tgz#40fdc3f9265ec0beae6f59824ade1bd3d3d2dab8" @@ -437,6 +479,64 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsonwebtoken@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== lru-cache@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" @@ -454,6 +554,10 @@ mime-types@^2.1.12: dependencies: mime-db "1.51.0" +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== node-domexception@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" @@ -468,11 +572,25 @@ node-fetch@^3.3.2: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" +once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" resolve-pkg-maps@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== +safe-buffer@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +semver@^7.5.4: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== tsx@^4.8.2: version "4.19.0" resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.19.0.tgz#6166cb399b17d14d125e6158d23384045cfdf4f6" @@ -493,10 +611,17 @@ undici-types@~6.19.2: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== -universal-github-app-jwt@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-2.2.0.tgz#dc6c8929e76f1996a766ba2a08fb420f73365d77" - integrity sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ== +universal-github-app-jwt@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-1.1.2.tgz#8c1867a394d7d9d42cda34f11d1bcb023797d8df" + integrity sha512-t1iB2FmLFE+yyJY9+3wMx0ejB+MQpEVkH0gQv7dR6FZyltyq+ZZO0uDpbopxhrZ3SLEO4dCEkIujOMldEQ2iOA== + dependencies: + "@types/jsonwebtoken" "^9.0.0" + jsonwebtoken "^9.0.2" +universal-user-agent@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" + integrity sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ== universal-user-agent@^7.0.0, universal-user-agent@^7.0.2: version "7.0.2" @@ -507,3 +632,7 @@ web-streams-polyfill@^3.0.3: version "3.2.1" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== From d7adef0123b476c852bc46c74bcd9fac35ad459c Mon Sep 17 00:00:00 2001 From: ztefanie Date: Thu, 24 Oct 2024 13:31:49 +0200 Subject: [PATCH 09/29] 2945: fix linting --- .../endpoints/__tests__/createChatMessagesEndpoint.spec.ts | 1 + shared/api/endpoints/createSendChatMessageEndpoint.ts | 1 + web/src/components/ChatMessage.tsx | 5 +++-- web/src/components/__tests__/ChatConversation.spec.tsx | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/shared/api/endpoints/__tests__/createChatMessagesEndpoint.spec.ts b/shared/api/endpoints/__tests__/createChatMessagesEndpoint.spec.ts index 38e5f6fd5a..e5e434b232 100644 --- a/shared/api/endpoints/__tests__/createChatMessagesEndpoint.spec.ts +++ b/shared/api/endpoints/__tests__/createChatMessagesEndpoint.spec.ts @@ -32,6 +32,7 @@ describe('createChatMessagesEndpoint', () => { id: 2, body: 'Informationen zu Ihrer Frage finden Sie auf folgenden Seiten:', userIsAuthor: false, + automaticAnswer: false, }), ]) }) diff --git a/shared/api/endpoints/createSendChatMessageEndpoint.ts b/shared/api/endpoints/createSendChatMessageEndpoint.ts index 8ef8f56bf1..a5a669531a 100644 --- a/shared/api/endpoints/createSendChatMessageEndpoint.ts +++ b/shared/api/endpoints/createSendChatMessageEndpoint.ts @@ -30,6 +30,7 @@ export default (baseUrl: string): Endpoint => id: json.id, body: json.body, userIsAuthor: json.user_is_author, + automaticAnswer: json.automatic_answer, }), ) .build() diff --git a/web/src/components/ChatMessage.tsx b/web/src/components/ChatMessage.tsx index 95656adf86..c4422d6f76 100644 --- a/web/src/components/ChatMessage.tsx +++ b/web/src/components/ChatMessage.tsx @@ -1,3 +1,4 @@ +import { TFunction } from 'i18next' import React, { ReactElement } from 'react' import { useTranslation } from 'react-i18next' import { useNavigate } from 'react-router-dom' @@ -50,7 +51,7 @@ const Circle = styled.div` type ChatMessageProps = { message: ChatMessageModel; showIcon: boolean } -const getIcon = (userIsAuthor: boolean, isAutomaticAnswer: boolean): ReactElement => { +const getIcon = (userIsAuthor: boolean, isAutomaticAnswer: boolean, t: TFunction<'chat'>): ReactElement => { if (userIsAuthor) { return {t('user')} } @@ -65,7 +66,7 @@ const ChatMessage = ({ message, showIcon }: ChatMessageProps): ReactElement => { return ( - {getIcon(userIsAuthor, isAutomaticAnswer)} + {getIcon(userIsAuthor, isAutomaticAnswer, t)} diff --git a/web/src/components/__tests__/ChatConversation.spec.tsx b/web/src/components/__tests__/ChatConversation.spec.tsx index 819d6cc208..023718b42d 100644 --- a/web/src/components/__tests__/ChatConversation.spec.tsx +++ b/web/src/components/__tests__/ChatConversation.spec.tsx @@ -19,11 +19,13 @@ describe('ChatConversation', () => { id: 1, body: 'Meine Frage lautet, warum bei Integreat eigentlich alles gelb ist. Weitere Infos', userIsAuthor: true, + automaticAnswer: false, }), new ChatMessageModel({ id: 2, body: 'Informationen zu Ihrer Frage finden Sie auf folgenden Seiten:', userIsAuthor: false, + automaticAnswer: false, }), ] From 71f8c51ba2cdbf04aa1de4ae8b9af4129d0705c3 Mon Sep 17 00:00:00 2001 From: Simon Kleinle Date: Thu, 24 Oct 2024 13:53:38 +0200 Subject: [PATCH 10/29] 2577: Revert yarn.lock --- tools/yarn.lock | 258 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 206 insertions(+), 52 deletions(-) diff --git a/tools/yarn.lock b/tools/yarn.lock index c656fca106..53259e91d6 100644 --- a/tools/yarn.lock +++ b/tools/yarn.lock @@ -136,37 +136,40 @@ universal-github-app-jwt "^2.2.0" universal-user-agent "^7.0.0" -"@octokit/auth-oauth-app@^8.1.0": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz#6204affa6e86f535016799cadf2af9befe5e893c" - integrity sha512-5UtmxXAvU2wfcHIPPDWzVSAWXVJzG3NWsxb7zCFplCWEmMCArSZV0UQu5jw5goLQXbFyOr5onzEH37UJB3zQQg== +"@octokit/auth-oauth-app@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-app/-/auth-oauth-app-7.1.0.tgz#d0f74e19ebd5a4829cb780c107cedd6c894f20fc" + integrity sha512-w+SyJN/b0l/HEb4EOPRudo7uUOSW51jcK1jwLa+4r7PA8FPFpoxEnHBHMITqCsc/3Vo2qqFjgQfz/xUUvsSQnA== dependencies: - "@octokit/auth-oauth-device" "^7.0.0" - "@octokit/auth-oauth-user" "^5.0.1" - "@octokit/request" "^9.0.0" + "@octokit/auth-oauth-device" "^6.1.0" + "@octokit/auth-oauth-user" "^4.1.0" + "@octokit/request" "^8.3.1" "@octokit/types" "^13.0.0" - universal-user-agent "^7.0.0" - -"@octokit/auth-oauth-device@^7.0.0", "@octokit/auth-oauth-device@^7.0.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.1.tgz#7b4f8f97cbcadbe9894d48cde4406dbdef39875a" - integrity sha512-HWl8lYueHonuyjrKKIup/1tiy0xcmQCdq5ikvMO1YwkNNkxb6DXfrPjrMYItNLyCP/o2H87WuijuE+SlBTT8eg== + "@types/btoa-lite" "^1.0.0" + btoa-lite "^1.0.0" + universal-user-agent "^6.0.0" + +"@octokit/auth-oauth-device@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-device/-/auth-oauth-device-6.1.0.tgz#f868213a3db05fe27e68d1fc607502a322379dd9" + integrity sha512-FNQ7cb8kASufd6Ej4gnJ3f1QB5vJitkoV1O0/g6e6lUsQ7+VsSNRHRmFScN2tV4IgKA12frrr/cegUs0t+0/Lw== dependencies: - "@octokit/oauth-methods" "^5.0.0" - "@octokit/request" "^9.0.0" + "@octokit/oauth-methods" "^4.1.0" + "@octokit/request" "^8.3.1" "@octokit/types" "^13.0.0" - universal-user-agent "^7.0.0" + universal-user-agent "^6.0.0" -"@octokit/auth-oauth-user@^5.0.1", "@octokit/auth-oauth-user@^5.1.0": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.1.tgz#4f1570c6ee15bb9ddc3dcca83308dcaa159e3848" - integrity sha512-rRkMz0ErOppdvEfnemHJXgZ9vTPhBuC6yASeFaB7I2yLMd7QpjfrL1mnvRPlyKo+M6eeLxrKanXJ9Qte29SRsw== +"@octokit/auth-oauth-user@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-user/-/auth-oauth-user-4.1.0.tgz#32e5529f8bd961af9839a1f8c6ab0c8ad2184eee" + integrity sha512-FrEp8mtFuS/BrJyjpur+4GARteUCrPeR/tZJzD8YourzoVhRics7u7we/aDcKv+yywRNwNi/P4fRi631rG/OyQ== dependencies: - "@octokit/auth-oauth-device" "^7.0.1" - "@octokit/oauth-methods" "^5.0.0" - "@octokit/request" "^9.0.1" + "@octokit/auth-oauth-device" "^6.1.0" + "@octokit/oauth-methods" "^4.1.0" + "@octokit/request" "^8.3.1" "@octokit/types" "^13.0.0" - universal-user-agent "^7.0.0" + btoa-lite "^1.0.0" + universal-user-agent "^6.0.0" "@octokit/auth-token@^5.0.0": version "5.1.1" @@ -194,6 +197,14 @@ "@octokit/types" "^13.0.0" universal-user-agent "^7.0.2" +"@octokit/endpoint@^9.0.1": + version "9.0.5" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.5.tgz#e6c0ee684e307614c02fc6ac12274c50da465c44" + integrity sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw== + dependencies: + "@octokit/types" "^13.1.0" + universal-user-agent "^6.0.0" + "@octokit/graphql@^8.0.0": version "8.1.1" resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-8.1.1.tgz#3cacab5f2e55d91c733e3bf481d3a3f8a5f639c4" @@ -203,20 +214,21 @@ "@octokit/types" "^13.0.0" universal-user-agent "^7.0.0" -"@octokit/oauth-authorization-url@^7.0.0": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz#0e17c2225eb66b58ec902d02b6f1315ffe9ff04b" - integrity sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA== +"@octokit/oauth-authorization-url@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-6.0.2.tgz#cc82ca29cc5e339c9921672f39f2b3f5c8eb6ef2" + integrity sha512-CdoJukjXXxqLNK4y/VOiVzQVjibqoj/xHgInekviUJV73y/BSIcwvJ/4aNHPBPKcPWFnd4/lO9uqRV65jXhcLA== -"@octokit/oauth-methods@^5.0.0": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@octokit/oauth-methods/-/oauth-methods-5.1.2.tgz#fd31d2a69f4c91d1abc1ed1814dda5252c697e02" - integrity sha512-C5lglRD+sBlbrhCUTxgJAFjWgJlmTx5bQ7Ch0+2uqRjYv7Cfb5xpX4WuSC9UgQna3sqRGBL9EImX9PvTpMaQ7g== +"@octokit/oauth-methods@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@octokit/oauth-methods/-/oauth-methods-4.1.0.tgz#1403ac9c4d4e277922fddc4c89fa8a782f8f791b" + integrity sha512-4tuKnCRecJ6CG6gr0XcEXdZtkTDbfbnD5oaHBmLERTjTMZNi2CbfEHZxPU41xXLDG4DfKf+sonu00zvKI9NSbw== dependencies: - "@octokit/oauth-authorization-url" "^7.0.0" - "@octokit/request" "^9.1.0" - "@octokit/request-error" "^6.1.0" + "@octokit/oauth-authorization-url" "^6.0.2" + "@octokit/request" "^8.3.1" + "@octokit/request-error" "^5.1.0" "@octokit/types" "^13.0.0" + btoa-lite "^1.0.0" "@octokit/openapi-types@^22.1.0": version "22.1.0" @@ -247,6 +259,15 @@ dependencies: "@octokit/types" "^13.5.0" +"@octokit/request-error@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.1.0.tgz#ee4138538d08c81a60be3f320cd71063064a3b30" + integrity sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q== + dependencies: + "@octokit/types" "^13.1.0" + deprecation "^2.0.0" + once "^1.4.0" + "@octokit/request-error@^6.0.1": version "6.1.4" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.4.tgz#ad96e29148d19edc2ba8009fc2b5a24a36c90f16" @@ -254,14 +275,17 @@ dependencies: "@octokit/types" "^13.0.0" -"@octokit/request-error@^6.1.0", "@octokit/request-error@^6.1.1": - version "6.1.5" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.5.tgz#907099e341c4e6179db623a0328d678024f54653" - integrity sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ== +"@octokit/request@^8.3.1": + version "8.4.0" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.4.0.tgz#7f4b7b1daa3d1f48c0977ad8fffa2c18adef8974" + integrity sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw== dependencies: - "@octokit/types" "^13.0.0" + "@octokit/endpoint" "^9.0.1" + "@octokit/request-error" "^5.1.0" + "@octokit/types" "^13.1.0" + universal-user-agent "^6.0.0" -"@octokit/request@^9.0.0", "@octokit/request@^9.0.1", "@octokit/request@^9.1.0", "@octokit/request@^9.1.1": +"@octokit/request@^9.0.0": version "9.1.3" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-9.1.3.tgz#42b693bc06238f43af3c037ebfd35621c6457838" integrity sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA== @@ -288,13 +312,6 @@ dependencies: "@octokit/openapi-types" "^22.1.0" -"@octokit/types@^13.4.1": - version "13.6.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.6.1.tgz#432fc6c0aaae54318e5b2d3e15c22ac97fc9b15f" - integrity sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g== - dependencies: - "@octokit/openapi-types" "^22.2.0" - "@octokit/types@^13.5.0": version "13.5.0" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.5.0.tgz#4796e56b7b267ebc7c921dcec262b3d5bfb18883" @@ -302,11 +319,23 @@ dependencies: "@octokit/openapi-types" "^22.2.0" +"@types/btoa-lite@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/btoa-lite/-/btoa-lite-1.0.2.tgz#82bb6aab00abf7cff3ca2825abe010c0cd536ae5" + integrity sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg== + "@types/js-yaml@^4.0.9": version "4.0.9" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg== +"@types/jsonwebtoken@^9.0.0": + version "9.0.6" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz#d1af3544d99ad992fb6681bbe60676e06b032bd3" + integrity sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw== + dependencies: + "@types/node" "*" + "@types/node-fetch@^2.6.11": version "2.6.11" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" @@ -342,6 +371,16 @@ before-after-hook@^3.0.2: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-3.0.2.tgz#d5665a5fa8b62294a5aa0a499f933f4a1016195d" integrity sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A== +btoa-lite@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" + integrity sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA== + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -364,6 +403,18 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +deprecation@^2.0.0, deprecation@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + esbuild@~0.23.0: version "0.23.1" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.1.tgz#40fdc3f9265ec0beae6f59824ade1bd3d3d2dab8" @@ -437,6 +488,74 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsonwebtoken@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + lru-cache@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" @@ -454,6 +573,11 @@ mime-types@^2.1.12: dependencies: mime-db "1.51.0" +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + node-domexception@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" @@ -468,11 +592,28 @@ node-fetch@^3.3.2: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" +once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + resolve-pkg-maps@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== +safe-buffer@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +semver@^7.5.4: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + tsx@^4.8.2: version "4.19.0" resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.19.0.tgz#6166cb399b17d14d125e6158d23384045cfdf4f6" @@ -493,10 +634,18 @@ undici-types@~6.19.2: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== -universal-github-app-jwt@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-2.2.0.tgz#dc6c8929e76f1996a766ba2a08fb420f73365d77" - integrity sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ== +universal-github-app-jwt@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-1.1.2.tgz#8c1867a394d7d9d42cda34f11d1bcb023797d8df" + integrity sha512-t1iB2FmLFE+yyJY9+3wMx0ejB+MQpEVkH0gQv7dR6FZyltyq+ZZO0uDpbopxhrZ3SLEO4dCEkIujOMldEQ2iOA== + dependencies: + "@types/jsonwebtoken" "^9.0.0" + jsonwebtoken "^9.0.2" + +universal-user-agent@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" + integrity sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ== universal-user-agent@^7.0.0, universal-user-agent@^7.0.2: version "7.0.2" @@ -507,3 +656,8 @@ web-streams-polyfill@^3.0.3: version "3.2.1" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== From a2f35a425a1dddb21d4780d1323299c9f3ce0a53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 07:38:39 +0000 Subject: [PATCH 11/29] Bump http-proxy-middleware from 2.0.6 to 2.0.7 Bumps [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) from 2.0.6 to 2.0.7. - [Release notes](https://github.com/chimurai/http-proxy-middleware/releases) - [Changelog](https://github.com/chimurai/http-proxy-middleware/blob/v2.0.7/CHANGELOG.md) - [Commits](https://github.com/chimurai/http-proxy-middleware/compare/v2.0.6...v2.0.7) --- updated-dependencies: - dependency-name: http-proxy-middleware dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3f5b3d6971..591bdd3374 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9738,9 +9738,9 @@ http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.2: debug "^4.3.4" http-proxy-middleware@^2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" - integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== + version "2.0.7" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz#915f236d92ae98ef48278a95dedf17e991936ec6" + integrity sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA== dependencies: "@types/http-proxy" "^1.17.8" http-proxy "^1.18.1" From f238ef3be9617637f82eb7e03972fa66c9b7df47 Mon Sep 17 00:00:00 2001 From: Steffen Kleinle Date: Fri, 25 Oct 2024 12:40:00 +0200 Subject: [PATCH 12/29] 2924: Rename e2e testumgebung --- e2e-tests/shared/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/shared/constants.ts b/e2e-tests/shared/constants.ts index 9d50835dba..e4cad3e4a2 100644 --- a/e2e-tests/shared/constants.ts +++ b/e2e-tests/shared/constants.ts @@ -1,6 +1,6 @@ export const filter = 'wirschaffendas' export const contentSearch = 'language' -export const defaultCity = 'Testumgebung Ende-zu-Ende-Testing' +export const defaultCity = 'E2E-Testumgebung' export const augsburgCity = 'Stadt Augsburg' export const language = 'en' From e45c7a396d653053e9db8ee3d010273d4224b06d Mon Sep 17 00:00:00 2001 From: Steffen Kleinle Date: Fri, 25 Oct 2024 12:53:42 +0200 Subject: [PATCH 13/29] 2915: Fix test by mocking time --- shared/api/models/__tests__/EventModel.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/api/models/__tests__/EventModel.spec.ts b/shared/api/models/__tests__/EventModel.spec.ts index 08a35035b9..f543199373 100644 --- a/shared/api/models/__tests__/EventModel.spec.ts +++ b/shared/api/models/__tests__/EventModel.spec.ts @@ -6,6 +6,8 @@ import DateModel from '../DateModel' import EventModel from '../EventModel' import LocationModel from '../LocationModel' +jest.useFakeTimers({ now: new Date('2023-10-02T15:23:57.443+02:00') }) + describe('EventModel', () => { const params = { path: '/augsburg/de/events/event0', From 5ea8f7f03013b9c4a43f10868fcb803405c7862f Mon Sep 17 00:00:00 2001 From: "deliverino[bot]" <62934656+deliverino[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 03:58:24 +0000 Subject: [PATCH 14/29] Bump version name to 2024.10.3 and version code to 100042400 [skip ci] --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index a308dcc617..e0a5be2983 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"versionName":"2024.10.2","versionCode":100042399} \ No newline at end of file +{"versionName":"2024.10.3","versionCode":100042400} \ No newline at end of file From 4052a468998be2fd446bb34784f735443ce84c13 Mon Sep 17 00:00:00 2001 From: "deliverino[bot]" <62934656+deliverino[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 04:24:59 +0000 Subject: [PATCH 15/29] Move release notes to 2024.10.3 [skip ci] --- .../2805-Banner-to-install-app-from-store.yml | 0 release-notes/{unreleased => 2024.10.3}/2897-refresh-cities.yml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename release-notes/{unreleased => 2024.10.3}/2805-Banner-to-install-app-from-store.yml (100%) rename release-notes/{unreleased => 2024.10.3}/2897-refresh-cities.yml (100%) diff --git a/release-notes/unreleased/2805-Banner-to-install-app-from-store.yml b/release-notes/2024.10.3/2805-Banner-to-install-app-from-store.yml similarity index 100% rename from release-notes/unreleased/2805-Banner-to-install-app-from-store.yml rename to release-notes/2024.10.3/2805-Banner-to-install-app-from-store.yml diff --git a/release-notes/unreleased/2897-refresh-cities.yml b/release-notes/2024.10.3/2897-refresh-cities.yml similarity index 100% rename from release-notes/unreleased/2897-refresh-cities.yml rename to release-notes/2024.10.3/2897-refresh-cities.yml From 516300ddc36388d6e074db3ab4f9ac442ef58c66 Mon Sep 17 00:00:00 2001 From: Steffen Kleinle Date: Mon, 28 Oct 2024 12:34:43 +0100 Subject: [PATCH 16/29] 2953: Use android app bundles --- .circleci/config.yml | 10 ++++++++++ .circleci/src/jobs/build_android.yml | 10 ++++++++++ native/android/fastlane/Fastfile | 2 +- native/fastlane/Fastfile | 11 ++++++----- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 232b792e72..29698a9078 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -326,6 +326,16 @@ jobs: paths: - << parameters.build_config_name >>.apk root: native/android + - run: + command: mv app/build/outputs/bundle/release/app-release.aab << parameters.build_config_name >>.aab + name: Rename aab + working_directory: native/android + - store_artifacts: + path: native/android/<< parameters.build_config_name >>.aab + - persist_to_workspace: + paths: + - << parameters.build_config_name >>.aab + root: native/android - unless: condition: or: diff --git a/.circleci/src/jobs/build_android.yml b/.circleci/src/jobs/build_android.yml index a1516164ea..c8e5213882 100644 --- a/.circleci/src/jobs/build_android.yml +++ b/.circleci/src/jobs/build_android.yml @@ -70,6 +70,16 @@ steps: root: native/android paths: - << parameters.build_config_name >>.apk + - run: + name: Rename aab + command: mv app/build/outputs/bundle/release/app-release.aab << parameters.build_config_name >>.aab + working_directory: native/android + - store_artifacts: + path: native/android/<< parameters.build_config_name >>.aab + - persist_to_workspace: + root: native/android + paths: + - << parameters.build_config_name >>.aab - unless: condition: or: diff --git a/native/android/fastlane/Fastfile b/native/android/fastlane/Fastfile index f7a1f5c99f..108f47da94 100644 --- a/native/android/fastlane/Fastfile +++ b/native/android/fastlane/Fastfile @@ -68,7 +68,7 @@ lane :build do |options| end gradle( - task: "assembleRelease", + tasks: ["assembleRelease", "bundleRelease"], properties: { :BUILD_CONFIG_NAME => build_config_name, :VERSION_CODE => version_code, diff --git a/native/fastlane/Fastfile b/native/fastlane/Fastfile index d44554b317..d0a8505b6b 100644 --- a/native/fastlane/Fastfile +++ b/native/fastlane/Fastfile @@ -66,8 +66,8 @@ platform :android do # version_code: The version code of the app # version_name: The version name of the app # build_config_name: The name of the build config - # apk_path: The path of the apk to upload (relative to home dir) - # production_delivery: Whether the apk should be uploaded to the production track + # aab_path: The path of the aab to upload (relative to home dir) + # production_delivery: Whether the aab should be uploaded to the production track desc "Deliver the app to Play Store. Depending on the option `production_delivery` the update is released to the general public." lane :playstore_upload do |options| ensure_env_vars( @@ -77,10 +77,10 @@ platform :android do version_code = options[:version_code] version_name = options[:version_name] build_config_name = options[:build_config_name] - apk_path = options[:apk_path] + aab_path = options[:aab_path] production_delivery = options[:production_delivery] - if [version_name, version_code, build_config_name, apk_path, production_delivery].include?(nil) + if [version_name, version_code, build_config_name, aab_path, production_delivery].include?(nil) raise "'nil' passed as parameter! Aborting..." end @@ -102,7 +102,7 @@ platform :android do skip_upload_screenshots: skip_images, skip_upload_metadata: false, release_status: "completed", - apk: "#{ENV['HOME']}/#{apk_path}", + aab: "#{ENV['HOME']}/#{aab_path}", json_key_data: ENV["GOOGLE_SERVICE_ACCOUNT_JSON"] ) end @@ -153,6 +153,7 @@ platform :android do skip_upload_screenshots: true, skip_upload_metadata: true, skip_upload_apk: true, + skip_upload_aab: true, release_status: "completed", json_key_data: ENV["GOOGLE_SERVICE_ACCOUNT_JSON"] ) From eb864208fbf2ab61ebf3a72740656ede793a10a0 Mon Sep 17 00:00:00 2001 From: "deliverino[bot]" <62934656+deliverino[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:37:20 +0000 Subject: [PATCH 17/29] Bump version name to 2024.10.4 and version code to 100042401 [skip ci] --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index e0a5be2983..d0394553c3 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"versionName":"2024.10.3","versionCode":100042400} \ No newline at end of file +{"versionName":"2024.10.4","versionCode":100042401} \ No newline at end of file From ba1a69c2ba7b69503d239b39bd5e4f1e85b5d32a Mon Sep 17 00:00:00 2001 From: "deliverino[bot]" <62934656+deliverino[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:42:28 +0000 Subject: [PATCH 18/29] Bump version name to 2024.10.5 and version code to 100042402 [skip ci] --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index d0394553c3..5d9a5543a5 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"versionName":"2024.10.4","versionCode":100042401} \ No newline at end of file +{"versionName":"2024.10.5","versionCode":100042402} \ No newline at end of file From 7a76d4af1a7c8c2c0dfafc0d2341a3eaf683ad1e Mon Sep 17 00:00:00 2001 From: Steffen Kleinle Date: Mon, 28 Oct 2024 13:35:35 +0100 Subject: [PATCH 19/29] 2953: Fix aab path --- .circleci/config.yml | 2 +- .circleci/src/jobs/deliver_android.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 29698a9078..e9a73594b9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -579,7 +579,7 @@ jobs: name: '[FL] Browserstack Upload Live' working_directory: native - run: - command: bundle exec fastlane android playstore_upload build_config_name:<< parameters.build_config_name >> apk_path:attached_workspace/<< parameters.build_config_name >>.apk production_delivery:"<< parameters.production_delivery >>" version_name:${NEW_VERSION_NAME} version_code:${NEW_VERSION_CODE} + command: bundle exec fastlane android playstore_upload build_config_name:<< parameters.build_config_name >> aab_path:attached_workspace/<< parameters.build_config_name >>.aab production_delivery:"<< parameters.production_delivery >>" version_name:${NEW_VERSION_NAME} version_code:${NEW_VERSION_CODE} name: '[FL] Play Store Upload' working_directory: native - notify diff --git a/.circleci/src/jobs/deliver_android.yml b/.circleci/src/jobs/deliver_android.yml index 35d7c7cd6a..0fdd494385 100644 --- a/.circleci/src/jobs/deliver_android.yml +++ b/.circleci/src/jobs/deliver_android.yml @@ -32,6 +32,6 @@ steps: working_directory: native - run: name: '[FL] Play Store Upload' - command: bundle exec fastlane android playstore_upload build_config_name:<< parameters.build_config_name >> apk_path:attached_workspace/<< parameters.build_config_name >>.apk production_delivery:"<< parameters.production_delivery >>" version_name:${NEW_VERSION_NAME} version_code:${NEW_VERSION_CODE} + command: bundle exec fastlane android playstore_upload build_config_name:<< parameters.build_config_name >> aab_path:attached_workspace/<< parameters.build_config_name >>.aab production_delivery:"<< parameters.production_delivery >>" version_name:${NEW_VERSION_NAME} version_code:${NEW_VERSION_CODE} working_directory: native - notify From 69a2f01b6d8a5988c3d3788bdfdced8d11e8072f Mon Sep 17 00:00:00 2001 From: "deliverino[bot]" <62934656+deliverino[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:38:29 +0000 Subject: [PATCH 20/29] Bump version name to 2024.10.6 and version code to 100042403 [skip ci] --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 5d9a5543a5..fe4ef71e5d 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"versionName":"2024.10.5","versionCode":100042402} \ No newline at end of file +{"versionName":"2024.10.6","versionCode":100042403} \ No newline at end of file From b18fd1c89f63ea0c84d5a22ed6a443f3036302ab Mon Sep 17 00:00:00 2001 From: "deliverino[bot]" <62934656+deliverino[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 03:58:20 +0000 Subject: [PATCH 21/29] Bump version name to 2024.11.0 and version code to 100042404 [skip ci] --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index fe4ef71e5d..5993474957 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"versionName":"2024.10.6","versionCode":100042403} \ No newline at end of file +{"versionName":"2024.11.0","versionCode":100042404} \ No newline at end of file From ff3299c68027030870f54772be3bda4c51dc5c72 Mon Sep 17 00:00:00 2001 From: ztefanie Date: Mon, 4 Nov 2024 09:35:24 +0100 Subject: [PATCH 22/29] 2945: Fix linting --- web/src/components/ChatMessage.tsx | 1 - web/src/components/base/Icon.tsx | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/ChatMessage.tsx b/web/src/components/ChatMessage.tsx index c4422d6f76..4b494c6d01 100644 --- a/web/src/components/ChatMessage.tsx +++ b/web/src/components/ChatMessage.tsx @@ -7,7 +7,6 @@ import styled from 'styled-components' import ChatMessageModel from 'shared/api/models/ChatMessageModel' import { ChatBot, ChatPerson } from '../assets' -import buildConfig from '../constants/buildConfig' import RemoteContent from './RemoteContent' import Icon from './base/Icon' diff --git a/web/src/components/base/Icon.tsx b/web/src/components/base/Icon.tsx index 5309c52b41..a6dda65ca0 100644 --- a/web/src/components/base/Icon.tsx +++ b/web/src/components/base/Icon.tsx @@ -10,6 +10,7 @@ const StyledIcon = styled(SVG)<{ $directionDependent: boolean; $reverse: boolean color: ${props => props.theme.colors.textColor}; width: 24px; height: 24px; + --theme-color: ${props => props.theme.colors.themeColor}; ` From 27e20cd68b66f9c0b7e0ade1cb99ad20bf78f6bf Mon Sep 17 00:00:00 2001 From: ztefanie Date: Mon, 4 Nov 2024 10:50:42 +0100 Subject: [PATCH 23/29] 2945: Fix test --- .../api/endpoints/__tests__/createChatMessagesEndpoint.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/api/endpoints/__tests__/createChatMessagesEndpoint.spec.ts b/shared/api/endpoints/__tests__/createChatMessagesEndpoint.spec.ts index e5e434b232..12aa0ec449 100644 --- a/shared/api/endpoints/__tests__/createChatMessagesEndpoint.spec.ts +++ b/shared/api/endpoints/__tests__/createChatMessagesEndpoint.spec.ts @@ -23,6 +23,7 @@ describe('createChatMessagesEndpoint', () => { id: 2, body: 'Informationen zu Ihrer Frage finden Sie auf folgenden Seiten:', user_is_author: false, + automatic_answer: false, }, ], } From ee12b96690b7bc5500d1a53c728db6a6022a653d Mon Sep 17 00:00:00 2001 From: "deliverino[bot]" <62934656+deliverino[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 03:58:40 +0000 Subject: [PATCH 24/29] Bump version name to 2024.11.1 and version code to 100042405 [skip ci] --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 5993474957..d0a6272a38 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"versionName":"2024.11.0","versionCode":100042404} \ No newline at end of file +{"versionName":"2024.11.1","versionCode":100042405} \ No newline at end of file From 16aed0ea1c9d0fe3f7057ae28527bb6f27172d34 Mon Sep 17 00:00:00 2001 From: Steffen Kleinle Date: Mon, 11 Nov 2024 09:26:22 +0100 Subject: [PATCH 25/29] Speed up local development android builds --- native/run | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/native/run b/native/run index 912740166f..a93ab41d51 100755 --- a/native/run +++ b/native/run @@ -21,7 +21,7 @@ program .option('--production', 'whether a production (release) build should be made') .action((buildConfigName, options) => { const { production } = options - const productionFlag = production ? '--mode=release' : '' + const buildFlag = production ? '--mode=release' : '--active-arch-only' const jsonBuildConfig = execSync( `yarn workspace --silent build-configs --silent manage to-json ${buildConfigName} android`, @@ -34,7 +34,7 @@ program .toString() .replaceAll('\n', ' ') execSync( - `yarn cross-env ${buildConfig} yarn react-native run-android --no-packager --appId ${applicationId} ${productionFlag}`, + `yarn cross-env ${buildConfig} yarn react-native run-android --no-packager --appId ${applicationId} ${buildFlag}`, { stdio: 'inherit' }, ) }) From 4ba6c4ff821c64b91791b36f3469ca5fffbd3f15 Mon Sep 17 00:00:00 2001 From: Steffen Kleinle Date: Mon, 11 Nov 2024 09:49:28 +0100 Subject: [PATCH 26/29] 2350: Better naming and handle synchronous errors --- native/src/components/SettingItem.tsx | 2 +- native/src/routes/Settings.tsx | 8 +++++--- native/src/utils/createSettingsSections.ts | 23 +++++++++++++--------- translations/translations.json | 4 ++-- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/native/src/components/SettingItem.tsx b/native/src/components/SettingItem.tsx index f73dac6eba..fb47868e76 100644 --- a/native/src/components/SettingItem.tsx +++ b/native/src/components/SettingItem.tsx @@ -45,7 +45,7 @@ const Badge = styled.View<{ enabled: boolean }>` type SettingItemProps = { title: string description?: string - onPress: () => void + onPress: () => Promise bigTitle?: boolean role?: Role hasSwitch?: boolean diff --git a/native/src/routes/Settings.tsx b/native/src/routes/Settings.tsx index 66e176e8fb..f911125b85 100644 --- a/native/src/routes/Settings.tsx +++ b/native/src/routes/Settings.tsx @@ -34,14 +34,16 @@ const Settings = ({ navigation }: SettingsProps): ReactElement => { const { t } = useTranslation('settings') const { settings } = appContext - const safeOnPress = (update: () => Promise | void) => () => { + const safeOnPress = (update: () => Promise | void) => async () => { const oldSettings = settings - update()?.catch(e => { + try { + await update() + } catch (e) { log('Failed to persist settings.', 'error') reportError(e) appContext.updateSettings(oldSettings) showSnackbar({ text: t('error:unknownError') }) - }) + } } const renderItem = ({ item }: { item: SettingsSectionType }) => { diff --git a/native/src/utils/createSettingsSections.ts b/native/src/utils/createSettingsSections.ts index e10a547358..40a837519b 100644 --- a/native/src/utils/createSettingsSections.ts +++ b/native/src/utils/createSettingsSections.ts @@ -62,9 +62,9 @@ const createSettingsSections = ({ hasSwitch: true, getSettingValue: (settings: SettingsType) => settings.allowPushNotifications, onPress: async () => { - const allowPushNotifications = !settings.allowPushNotifications - updateSettings({ allowPushNotifications }) - if (!allowPushNotifications) { + const newAllowPushNotifications = !settings.allowPushNotifications + updateSettings({ allowPushNotifications: newAllowPushNotifications }) + if (!newAllowPushNotifications) { await unsubscribeNews(cityCode, languageCode) return } @@ -72,12 +72,17 @@ const createSettingsSections = ({ const status = await requestPushNotificationPermission(updateSettings) if (status) { - await subscribeNews({ cityCode, languageCode, allowPushNotifications, skipSettingsCheck: true }) + await subscribeNews({ + cityCode, + languageCode, + allowPushNotifications: newAllowPushNotifications, + skipSettingsCheck: true, + }) } else { updateSettings({ allowPushNotifications: false }) // If the user has rejected the permission once, it can only be changed in the system settings showSnackbar({ - text: 'noPushNotificationPermission', + text: 'permissionRequired', positiveAction: { label: t('layout:settings'), onPress: openSettings, @@ -95,14 +100,14 @@ const createSettingsSections = ({ hasSwitch: true, getSettingValue: (settings: SettingsType) => settings.errorTracking, onPress: async () => { - const errorTracking = !settings.errorTracking - updateSettings({ errorTracking }) + const newErrorTracking = !settings.errorTracking + updateSettings({ errorTracking: newErrorTracking }) const client = Sentry.getClient() - if (errorTracking && !client) { + if (newErrorTracking && !client) { initSentry() } else if (client) { - client.getOptions().enabled = errorTracking + client.getOptions().enabled = newErrorTracking } }, }, diff --git a/translations/translations.json b/translations/translations.json index 1ea0ec636d..2a8d010504 100644 --- a/translations/translations.json +++ b/translations/translations.json @@ -2338,7 +2338,7 @@ "notSupportedByDevice": "Diese Funktion wird auf diesem Gerät nicht unterstützt.", "languageSwitchFailedTitle": "Leider ist der Sprachwechsel fehlgeschlagen.", "languageSwitchFailedMessage": "Die ausgewählte Sprache ist nicht offline verfügbar. Eine aktive Internetverbinding ist notwendig.", - "noPushNotificatidbonPermission": "Berechtigung erforderlich", + "permissionRequired": "Berechtigung erforderlich", "noCalendarPermission": "Der Zugriff auf den Kalender ist nicht erlaubt.", "noCalendarFound": "Es wurde kein geeigneter Kalender gefunden." }, @@ -2619,7 +2619,7 @@ "notSupportedByDevice": "This function is not supported on this device.", "languageSwitchFailedTitle": "Unfortunately, changing the language failed.", "languageSwitchFailedMessage": "The selected language is not available if you are offline. An active internet connection is required.", - "noPushNotificationPermission": "Permission required", + "permissionRequired": "Permission required", "noCalendarPermission": "Access to the calendar is not permitted.", "noCalendarFound": "No suitable calendar was found." }, From a611e7f831cdcf2f22dce4e8c0436044af0fa476 Mon Sep 17 00:00:00 2001 From: Steffen Kleinle Date: Mon, 11 Nov 2024 13:32:45 +0100 Subject: [PATCH 27/29] 2350: Add custom error message --- native/src/routes/Settings.tsx | 2 +- translations/translations.json | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/native/src/routes/Settings.tsx b/native/src/routes/Settings.tsx index f911125b85..37595d1c9d 100644 --- a/native/src/routes/Settings.tsx +++ b/native/src/routes/Settings.tsx @@ -42,7 +42,7 @@ const Settings = ({ navigation }: SettingsProps): ReactElement => { log('Failed to persist settings.', 'error') reportError(e) appContext.updateSettings(oldSettings) - showSnackbar({ text: t('error:unknownError') }) + showSnackbar({ text: t('error:settingsError') }) } } diff --git a/translations/translations.json b/translations/translations.json index 2a8d010504..972a262f69 100644 --- a/translations/translations.json +++ b/translations/translations.json @@ -2340,7 +2340,8 @@ "languageSwitchFailedMessage": "Die ausgewählte Sprache ist nicht offline verfügbar. Eine aktive Internetverbinding ist notwendig.", "permissionRequired": "Berechtigung erforderlich", "noCalendarPermission": "Der Zugriff auf den Kalender ist nicht erlaubt.", - "noCalendarFound": "Es wurde kein geeigneter Kalender gefunden." + "noCalendarFound": "Es wurde kein geeigneter Kalender gefunden.", + "settingsError": "Fehler beim Anwenden der Einstellungen" }, "am": { "notFound": { @@ -2621,7 +2622,8 @@ "languageSwitchFailedMessage": "The selected language is not available if you are offline. An active internet connection is required.", "permissionRequired": "Permission required", "noCalendarPermission": "Access to the calendar is not permitted.", - "noCalendarFound": "No suitable calendar was found." + "noCalendarFound": "No suitable calendar was found.", + "settingsError": "Failed to apply settings" }, "es": { "notFound": { From 113fa066b288229321e7275f154f60839c775448 Mon Sep 17 00:00:00 2001 From: Steffen Kleinle Date: Mon, 11 Nov 2024 13:48:51 +0100 Subject: [PATCH 28/29] 2924: Catch SecurityError when accessing localStorage --- .../unreleased/2924-security-error.yml | 5 ++ .../hooks/__tests__/useLocalStorage.spec.tsx | 75 +++++++++++++++++++ web/src/hooks/useLocalStorage.ts | 30 ++++++-- 3 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 release-notes/unreleased/2924-security-error.yml create mode 100644 web/src/hooks/__tests__/useLocalStorage.spec.tsx diff --git a/release-notes/unreleased/2924-security-error.yml b/release-notes/unreleased/2924-security-error.yml new file mode 100644 index 0000000000..1c5f94a204 --- /dev/null +++ b/release-notes/unreleased/2924-security-error.yml @@ -0,0 +1,5 @@ +issue_key: 2924 +show_in_stores: false +platforms: + - web +en: Fix crashes if local storage is not available diff --git a/web/src/hooks/__tests__/useLocalStorage.spec.tsx b/web/src/hooks/__tests__/useLocalStorage.spec.tsx new file mode 100644 index 0000000000..71cc7a926e --- /dev/null +++ b/web/src/hooks/__tests__/useLocalStorage.spec.tsx @@ -0,0 +1,75 @@ +import { fireEvent, render } from '@testing-library/react' +import React from 'react' + +import Button from '../../components/base/Button' +import useLocalStorage from '../useLocalStorage' + +describe('useLocalStorage', () => { + const key = 'my_storage_key' + const MockComponent = () => { + const { value, updateLocalStorageItem } = useLocalStorage({ key, initialValue: 0 }) + return ( +
+ {value} + +
+ ) + } + + beforeEach(() => { + jest.clearAllMocks() + localStorage.clear() + }) + + it('should correctly set initial value and update value', () => { + const { getByText } = render() + + expect(getByText(0)).toBeTruthy() + expect(localStorage.getItem(key)).toBe('0') + + fireEvent.click(getByText('Increment')) + + expect(getByText(1)).toBeTruthy() + expect(localStorage.getItem(key)).toBe('1') + + fireEvent.click(getByText('Increment')) + fireEvent.click(getByText('Increment')) + fireEvent.click(getByText('Increment')) + + expect(getByText(4)).toBeTruthy() + expect(localStorage.getItem(key)).toBe('4') + }) + + it('should not use initial value if already set', () => { + localStorage.setItem(key, '10') + const { getByText } = render() + + expect(getByText(10)).toBeTruthy() + expect(localStorage.getItem(key)).toBe('10') + + fireEvent.click(getByText('Increment')) + + expect(getByText(11)).toBeTruthy() + expect(localStorage.getItem(key)).toBe('11') + }) + + it('should continue to work even if local storage is not usable', () => { + localStorage.getItem = () => { + throw new Error('SecurityError') + } + localStorage.setItem = () => { + throw new Error('SecurityError') + } + const { getByText } = render() + + expect(getByText(0)).toBeTruthy() + expect(localStorage.getItem(key)).toBe('0') + + fireEvent.click(getByText('Increment')) + + expect(getByText(1)).toBeTruthy() + expect(localStorage.getItem(key)).toBe('1') + }) +}) diff --git a/web/src/hooks/useLocalStorage.ts b/web/src/hooks/useLocalStorage.ts index 24e861697c..cb3d20abdd 100644 --- a/web/src/hooks/useLocalStorage.ts +++ b/web/src/hooks/useLocalStorage.ts @@ -1,5 +1,7 @@ import { useState, useCallback } from 'react' +import { reportError } from '../utils/sentry' + type UseLocalStorageProps = { key: string initialValue: T @@ -12,17 +14,35 @@ type UseLocalStorageReturn = { const useLocalStorage = ({ key, initialValue }: UseLocalStorageProps): UseLocalStorageReturn => { const [value, setValue] = useState(() => { - const localStorageItem = localStorage.getItem(key) - if (localStorageItem) { - return JSON.parse(localStorageItem) + try { + const localStorageItem = localStorage.getItem(key) + if (localStorageItem) { + return JSON.parse(localStorageItem) + } + localStorage.setItem(key, JSON.stringify(initialValue)) + } catch (e) { + // Prevent the following error crashing the app if the browser blocks access to local storage (see #2924) + // SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document. + const accessDenied = e instanceof Error && e.message.includes('Access is denied for this document') + if (!accessDenied) { + reportError(e) + } } - localStorage.setItem(key, JSON.stringify(initialValue)) return initialValue }) const updateLocalStorageItem = useCallback( (newValue: T) => { - localStorage.setItem(key, JSON.stringify(newValue)) + try { + localStorage.setItem(key, JSON.stringify(newValue)) + } catch (e) { + // Prevent the following error crashing the app if the browser blocks access to local storage (see #2924) + // SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document. + const accessDenied = e instanceof Error && e.message.includes('Access is denied for this document') + if (!accessDenied) { + reportError(e) + } + } setValue(newValue) }, [key], From 18e17636ee8ed0bf6294aca90bae57fee69c174e Mon Sep 17 00:00:00 2001 From: Simon Kleinle Date: Mon, 11 Nov 2024 15:23:12 +0100 Subject: [PATCH 29/29] 2577: Add warning color to native feedback --- native/src/components/Note.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/src/components/Note.tsx b/native/src/components/Note.tsx index a930bcdc9a..efc96a39c2 100644 --- a/native/src/components/Note.tsx +++ b/native/src/components/Note.tsx @@ -5,7 +5,7 @@ import { NoteIcon } from '../assets' import Icon from './base/Icon' const NoteBox = styled.View` - background-color: ${props => props.theme.colors.themeColor}; + background-color: ${props => props.theme.colors.warningColor}; margin-top: 12px; padding: 12px; flex-direction: row;