Skip to content

Commit 562ae36

Browse files
committed
RU-T49 PR#232 fixes
1 parent 672825d commit 562ae36

File tree

37 files changed

+2230
-2271
lines changed

37 files changed

+2230
-2271
lines changed

jest-setup.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
import '@testing-library/react-native/extend-expect';
22

3+
// Mock @sentry/react-native — native module (RNSentry) is unavailable in Jest
4+
jest.mock('@sentry/react-native', () => ({
5+
captureException: jest.fn(),
6+
captureMessage: jest.fn(),
7+
init: jest.fn(),
8+
wrap: jest.fn((fn: any) => fn),
9+
withScope: jest.fn((cb: any) => cb({ setExtra: jest.fn(), setTag: jest.fn() })),
10+
setUser: jest.fn(),
11+
setTag: jest.fn(),
12+
setExtra: jest.fn(),
13+
addBreadcrumb: jest.fn(),
14+
configureScope: jest.fn(),
15+
ReactNavigationInstrumentation: jest.fn(),
16+
ReactNativeTracing: jest.fn(),
17+
}));
18+
319
// react-hook form setup for testing
420
// @ts-ignore
521
global.window = {};

src/api/mapping/mapping.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { type FeatureCollection } from 'geojson';
22

3+
import { getBaseApiUrl } from '@/lib/storage/app';
34
import { type GetMapDataAndMarkersResult } from '@/models/v4/mapping/getMapDataAndMarkersResult';
45
import { type GetMapLayersResult } from '@/models/v4/mapping/getMapLayersResult';
56
import {
67
type GetAllActiveLayersResult,
8+
type GetCustomMapLayerResult,
79
type GetCustomMapResult,
810
type GetCustomMapsResult,
911
type GetGeoJSONResult,
@@ -132,7 +134,7 @@ export const getCustomMap = async (mapId: string) => {
132134
};
133135

134136
export const getCustomMapLayer = async (layerId: string) => {
135-
const response = await getCustomMapLayerApi.get<GetGeoJSONResult>({
137+
const response = await getCustomMapLayerApi.get<GetCustomMapLayerResult>({
136138
layerId: encodeURIComponent(layerId),
137139
});
138140
return response.data;
@@ -180,13 +182,13 @@ export const searchAllMapFeatures = async (term: string, type?: 'all' | 'indoor'
180182
// --- URL Helpers (no fetch needed, constructs URLs for components) ---
181183

182184
export const getFloorImageUrl = (floorId: string): string => {
183-
return `/api/v4/Mapping/GetIndoorMapFloorImage/${encodeURIComponent(floorId)}`;
185+
return `${getBaseApiUrl()}/Mapping/GetIndoorMapFloorImage/${encodeURIComponent(floorId)}`;
184186
};
185187

186188
export const getCustomMapLayerImageUrl = (layerId: string): string => {
187-
return `/api/v4/Mapping/GetCustomMapLayerImage/${encodeURIComponent(layerId)}`;
189+
return `${getBaseApiUrl()}/Mapping/GetCustomMapLayerImage/${encodeURIComponent(layerId)}`;
188190
};
189191

190192
export const getCustomMapTileUrl = (layerId: string): string => {
191-
return `/api/v4/Mapping/GetCustomMapTile/${encodeURIComponent(layerId)}/{z}/{x}/{y}`;
193+
return `${getBaseApiUrl()}/Mapping/GetCustomMapTile/${encodeURIComponent(layerId)}/{z}/{x}/{y}`;
192194
};

src/api/routes/routes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import {
1919
type GetDirectionsResult,
2020
type GetRouteDeviationsResult,
2121
type GetRouteInstanceResult,
22-
type GetRouteInstanceStopsResult,
2322
type GetRouteInstancesResult,
23+
type GetRouteInstanceStopsResult,
2424
type GetRoutePlanResult,
2525
type GetRoutePlansResult,
2626
type GetRouteProgressResult,

src/app/(app)/_layout.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ export default function TabLayout() {
5353
useEffect(() => {
5454
if (status === 'signedIn' && userId) {
5555
try {
56-
Countly.userProfile.setUserProperties({ id: userId });
57-
Countly.userProfile.save();
56+
Countly.setUserData({ custom: { id: userId } });
5857
} catch {
5958
// Countly may not be initialized (e.g., no app key configured) — ignore
6059
}
@@ -68,7 +67,6 @@ export default function TabLayout() {
6867
useEffect(() => {
6968
if (Platform.OS !== 'android') return;
7069
NavigationBar.setVisibilityAsync('hidden');
71-
NavigationBar.setBehaviorAsync('overlay-swipe');
7270
const subscription = NavigationBar.addVisibilityListener(({ visibility }) => {
7371
if (visibility === 'visible') {
7472
NavigationBar.setVisibilityAsync('hidden');

src/app/(app)/index.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,7 @@ function MapContent() {
146146
const radiusDeg = nextStop.GeofenceRadiusMeters / 111320;
147147
for (let i = 0; i <= points; i++) {
148148
const angle = (i / points) * 2 * Math.PI;
149-
coords.push([
150-
nextStop.Longitude + radiusDeg * Math.cos(angle),
151-
nextStop.Latitude + radiusDeg * Math.sin(angle),
152-
]);
149+
coords.push([nextStop.Longitude + radiusDeg * Math.cos(angle), nextStop.Latitude + radiusDeg * Math.sin(angle)]);
153150
}
154151
return {
155152
type: 'Feature',
@@ -549,11 +546,7 @@ function MapContent() {
549546
{showRouteOverlay
550547
? remainingStops.map((stop) =>
551548
stop.Latitude && stop.Longitude ? (
552-
<Mapbox.PointAnnotation
553-
key={`route-stop-${stop.RouteInstanceStopId}`}
554-
id={`route-stop-${stop.RouteInstanceStopId}`}
555-
coordinate={[stop.Longitude, stop.Latitude]}
556-
>
549+
<Mapbox.PointAnnotation key={`route-stop-${stop.RouteInstanceStopId}`} id={`route-stop-${stop.RouteInstanceStopId}`} coordinate={[stop.Longitude, stop.Latitude]}>
557550
<StopMarker stopOrder={stop.StopOrder} status={stop.Status} />
558551
</Mapbox.PointAnnotation>
559552
) : null

src/app/(app)/routes.tsx

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import React, { useEffect, useMemo, useState } from 'react';
44
import { useTranslation } from 'react-i18next';
55
import { Pressable, RefreshControl, View } from 'react-native';
66

7-
import { RouteCard } from '@/components/routes/route-card';
87
import { Loading } from '@/components/common/loading';
98
import ZeroState from '@/components/common/zero-state';
9+
import { RouteCard } from '@/components/routes/route-card';
1010
import { Badge, BadgeText } from '@/components/ui/badge';
1111
import { Box } from '@/components/ui/box';
1212
import { Fab, FabIcon } from '@/components/ui/fab';
@@ -33,10 +33,7 @@ export default function Routes() {
3333
const fetchUnits = useUnitsStore((state) => state.fetchUnits);
3434
const [searchQuery, setSearchQuery] = useState('');
3535

36-
const unitMap = useMemo(
37-
() => Object.fromEntries(units.map((u) => [u.UnitId, u.Name])),
38-
[units]
39-
);
36+
const unitMap = useMemo(() => Object.fromEntries(units.map((u) => [u.UnitId, u.Name])), [units]);
4037

4138
useEffect(() => {
4239
fetchAllRoutePlans();
@@ -58,9 +55,7 @@ export default function Routes() {
5855
const handleRoutePress = (route: RoutePlanResultData) => {
5956
if (activeInstance && activeInstance.RoutePlanId === route.RoutePlanId) {
6057
const iid = activeInstance.RouteInstanceId;
61-
const url = iid && iid !== 'undefined'
62-
? `/routes/active?planId=${route.RoutePlanId}&instanceId=${iid}`
63-
: `/routes/active?planId=${route.RoutePlanId}`;
58+
const url = iid && iid !== 'undefined' ? `/routes/active?planId=${route.RoutePlanId}&instanceId=${iid}` : `/routes/active?planId=${route.RoutePlanId}`;
6459
router.push(url as any);
6560
} else {
6661
router.push(`/routes/start?planId=${route.RoutePlanId}` as any);
@@ -73,12 +68,8 @@ export default function Routes() {
7368
const q = searchQuery.toLowerCase();
7469
return active.filter((route) => {
7570
const isRouteMyUnit = route.UnitId != null && String(route.UnitId) === String(activeUnitId);
76-
const unitName = route.UnitId != null ? (unitMap[route.UnitId] || (isRouteMyUnit ? (activeUnit?.Name ?? '') : '')) : '';
77-
return (
78-
route.Name.toLowerCase().includes(q) ||
79-
(route.Description?.toLowerCase() || '').includes(q) ||
80-
unitName.toLowerCase().includes(q)
81-
);
71+
const unitName = route.UnitId != null ? unitMap[route.UnitId] || (isRouteMyUnit ? (activeUnit?.Name ?? '') : '') : '';
72+
return route.Name.toLowerCase().includes(q) || (route.Description?.toLowerCase() || '').includes(q) || unitName.toLowerCase().includes(q);
8273
});
8374
}, [routePlans, searchQuery, unitMap, activeUnitId, activeUnit]);
8475

@@ -100,29 +91,23 @@ export default function Routes() {
10091
<Pressable
10192
onPress={() => {
10293
const iid = activeInstance.RouteInstanceId;
103-
const url = iid && iid !== 'undefined'
104-
? `/routes/active?planId=${activeInstance.RoutePlanId}&instanceId=${iid}`
105-
: `/routes/active?planId=${activeInstance.RoutePlanId}`;
94+
const url = iid && iid !== 'undefined' ? `/routes/active?planId=${activeInstance.RoutePlanId}&instanceId=${iid}` : `/routes/active?planId=${activeInstance.RoutePlanId}`;
10695
router.push(url as any);
10796
}}
10897
>
10998
<Box className="mb-3 rounded-xl border-2 border-green-500 bg-green-50 p-4 dark:bg-green-900/20">
11099
<HStack className="items-center justify-between">
111100
<HStack className="items-center space-x-2">
112101
<Navigation size={20} color="#22c55e" />
113-
<Text className="text-base font-bold text-green-800 dark:text-green-200">
114-
{activeInstance.RoutePlanName || t('routes.active_route')}
115-
</Text>
102+
<Text className="text-base font-bold text-green-800 dark:text-green-200">{activeInstance.RoutePlanName || t('routes.active_route')}</Text>
116103
</HStack>
117104
<Badge className="bg-green-500">
118105
<BadgeText className="text-white">{t('routes.active')}</BadgeText>
119106
</Badge>
120107
</HStack>
121108
<Text className="mt-1 text-sm text-green-700 dark:text-green-300">
122109
{t('routes.progress', {
123-
percent: activeInstance.StopsTotal
124-
? Math.round(((activeInstance.StopsCompleted ?? 0) / activeInstance.StopsTotal) * 100)
125-
: 0,
110+
percent: activeInstance.StopsTotal ? Math.round(((activeInstance.StopsCompleted ?? 0) / activeInstance.StopsTotal) * 100) : 0,
126111
})}
127112
</Text>
128113
</Box>
@@ -131,29 +116,16 @@ export default function Routes() {
131116
}
132117
renderItem={({ item }: { item: RoutePlanResultData }) => {
133118
const isMyUnit = item.UnitId != null && String(item.UnitId) === String(activeUnitId);
134-
const unitName = item.UnitId != null
135-
? (unitMap[item.UnitId] || (isMyUnit ? (activeUnit?.Name ?? '') : ''))
136-
: '';
119+
const unitName = item.UnitId != null ? unitMap[item.UnitId] || (isMyUnit ? (activeUnit?.Name ?? '') : '') : '';
137120
return (
138121
<Pressable onPress={() => handleRoutePress(item)}>
139-
<RouteCard
140-
route={item}
141-
isActive={!!activeInstance && activeInstance.RoutePlanId === item.RoutePlanId}
142-
unitName={unitName || undefined}
143-
isMyUnit={isMyUnit}
144-
/>
122+
<RouteCard route={item} isActive={!!activeInstance && activeInstance.RoutePlanId === item.RoutePlanId} unitName={unitName || undefined} isMyUnit={isMyUnit} />
145123
</Pressable>
146124
);
147125
}}
148126
keyExtractor={(item: RoutePlanResultData) => item.RoutePlanId}
149127
refreshControl={<RefreshControl refreshing={isLoading} onRefresh={handleRefresh} />}
150-
ListEmptyComponent={
151-
<ZeroState
152-
heading={t('routes.no_routes')}
153-
description={t('routes.no_routes_description_all')}
154-
icon={RefreshCcwDotIcon}
155-
/>
156-
}
128+
ListEmptyComponent={<ZeroState heading={t('routes.no_routes')} description={t('routes.no_routes_description_all')} icon={RefreshCcwDotIcon} />}
157129
contentContainerStyle={{ paddingBottom: 20 }}
158130
/>
159131
);

src/app/login/index.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,7 @@ export default function Login() {
5454
return (
5555
<>
5656
<FocusAwareStatusBar />
57-
<LoginForm
58-
onSubmit={onSubmit}
59-
isLoading={status === 'loading'}
60-
error={error ?? undefined}
61-
onServerUrlPress={() => setShowServerUrl(true)}
62-
onSsoPress={() => router.push('/login/sso')}
63-
/>
57+
<LoginForm onSubmit={onSubmit} isLoading={status === 'loading'} error={error ?? undefined} onServerUrlPress={() => setShowServerUrl(true)} onSsoPress={() => router.push('/login/sso')} />
6458

6559
<Modal
6660
isOpen={isErrorModalVisible}

src/app/login/login-form.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { zodResolver } from '@hookform/resolvers/zod';
22
import { AlertTriangle, EyeIcon, EyeOffIcon, Globe, LogIn, ShieldCheck } from 'lucide-react-native';
3+
import { ChevronDownIcon } from 'lucide-react-native';
34
import { useColorScheme } from 'nativewind';
45
import React, { useState } from 'react';
56
import type { SubmitHandler } from 'react-hook-form';
@@ -18,7 +19,6 @@ import { Text } from '@/components/ui/text';
1819
import colors from '@/constants/colors';
1920
import { translate, useSelectedLanguage } from '@/lib';
2021
import type { Language } from '@/lib/i18n/resources';
21-
import { ChevronDownIcon } from 'lucide-react-native';
2222

2323
// Function to create schema - makes it easier to mock for testing
2424
const createLoginFormSchema = () =>
@@ -48,7 +48,7 @@ export type LoginFormProps = {
4848
onSsoPress?: () => void;
4949
};
5050

51-
export const LoginForm = ({ onSubmit = () => { }, isLoading = false, error = undefined, onServerUrlPress, onSsoPress }: LoginFormProps) => {
51+
export const LoginForm = ({ onSubmit = () => {}, isLoading = false, error = undefined, onServerUrlPress, onSsoPress }: LoginFormProps) => {
5252
const { colorScheme } = useColorScheme();
5353
const { t, i18n: i18nInstance } = useTranslation();
5454
const { language, setLanguage } = useSelectedLanguage();
@@ -215,10 +215,7 @@ export const LoginForm = ({ onSubmit = () => { }, isLoading = false, error = und
215215
{/* Language selector */}
216216
<View className="mt-4 flex-row items-center justify-center gap-x-2">
217217
<Globe size={16} className="text-gray-400" />
218-
<Select
219-
onValueChange={(val) => setLanguage(val as Language)}
220-
selectedValue={language ?? i18nInstance.language}
221-
>
218+
<Select onValueChange={(val) => setLanguage(val as Language)} selectedValue={language ?? i18nInstance.language}>
222219
<SelectTrigger size="sm" variant="outline" className="min-w-[160px]">
223220
<SelectInput placeholder={t('settings.language')} />
224221
<SelectIcon as={ChevronDownIcon} className="mr-2" />

0 commit comments

Comments
 (0)