Skip to content

Commit 8864c15

Browse files
committed
RU-T46 PR#198 fixes
1 parent 15f8bc5 commit 8864c15

9 files changed

Lines changed: 88 additions & 95 deletions

File tree

src/api/calls/calls.ts

Lines changed: 34 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -83,33 +83,34 @@ export interface CloseCallRequest {
8383
note?: string;
8484
}
8585

86-
export const createCall = async (callData: CreateCallRequest) => {
87-
let dispatchList = '';
88-
89-
if (callData.dispatchEveryone) {
90-
dispatchList = '0';
91-
} else {
92-
const dispatchEntries: string[] = [];
93-
94-
if (callData.dispatchUsers) {
95-
//dispatchEntries.push(...callData.dispatchUsers.map((user) => `U:${user}`));
96-
dispatchEntries.push(...callData.dispatchUsers);
97-
}
98-
if (callData.dispatchGroups) {
99-
//dispatchEntries.push(...callData.dispatchGroups.map((group) => `G:${group}`));
100-
dispatchEntries.push(...callData.dispatchGroups);
101-
}
102-
if (callData.dispatchRoles) {
103-
//dispatchEntries.push(...callData.dispatchRoles.map((role) => `R:${role}`));
104-
dispatchEntries.push(...callData.dispatchRoles);
105-
}
106-
if (callData.dispatchUnits) {
107-
//dispatchEntries.push(...callData.dispatchUnits.map((unit) => `U:${unit}`));
108-
dispatchEntries.push(...callData.dispatchUnits);
109-
}
110-
111-
dispatchList = dispatchEntries.join('|');
86+
/**
87+
* Helper function to build the dispatch list string from dispatch data
88+
*/
89+
const buildDispatchList = (data: { dispatchEveryone?: boolean; dispatchUsers?: string[]; dispatchGroups?: string[]; dispatchRoles?: string[]; dispatchUnits?: string[] }): string => {
90+
if (data.dispatchEveryone) {
91+
return '0';
92+
}
93+
94+
const dispatchEntries: string[] = [];
95+
96+
if (data.dispatchUsers) {
97+
dispatchEntries.push(...data.dispatchUsers);
98+
}
99+
if (data.dispatchGroups) {
100+
dispatchEntries.push(...data.dispatchGroups);
112101
}
102+
if (data.dispatchRoles) {
103+
dispatchEntries.push(...data.dispatchRoles);
104+
}
105+
if (data.dispatchUnits) {
106+
dispatchEntries.push(...data.dispatchUnits);
107+
}
108+
109+
return dispatchEntries.join('|');
110+
};
111+
112+
export const createCall = async (callData: CreateCallRequest) => {
113+
const dispatchList = buildDispatchList(callData);
113114

114115
const data = {
115116
Name: callData.name,
@@ -127,45 +128,20 @@ export const createCall = async (callData: CreateCallRequest) => {
127128
};
128129

129130
const response = await createCallApi.post<SaveCallResult>(data);
130-
131+
131132
// Invalidate cache after successful mutation
132133
try {
133134
cacheManager.remove('/Calls/GetActiveCalls');
134135
} catch (error) {
135136
// Silently handle cache removal errors
136137
console.warn('Failed to invalidate calls cache:', error);
137138
}
138-
139+
139140
return response.data;
140141
};
141142

142143
export const updateCall = async (callData: UpdateCallRequest) => {
143-
let dispatchList = '';
144-
145-
if (callData.dispatchEveryone) {
146-
dispatchList = '0';
147-
} else {
148-
const dispatchEntries: string[] = [];
149-
150-
if (callData.dispatchUsers) {
151-
//dispatchEntries.push(...callData.dispatchUsers.map((user) => `U:${user}`));
152-
dispatchEntries.push(...callData.dispatchUsers);
153-
}
154-
if (callData.dispatchGroups) {
155-
//dispatchEntries.push(...callData.dispatchGroups.map((group) => `G:${group}`));
156-
dispatchEntries.push(...callData.dispatchGroups);
157-
}
158-
if (callData.dispatchRoles) {
159-
//dispatchEntries.push(...callData.dispatchRoles.map((role) => `R:${role}`));
160-
dispatchEntries.push(...callData.dispatchRoles);
161-
}
162-
if (callData.dispatchUnits) {
163-
//dispatchEntries.push(...callData.dispatchUnits.map((unit) => `U:${unit}`));
164-
dispatchEntries.push(...callData.dispatchUnits);
165-
}
166-
167-
dispatchList = dispatchEntries.join('|');
168-
}
144+
const dispatchList = buildDispatchList(callData);
169145

170146
const data = {
171147
CallId: callData.callId,
@@ -184,15 +160,15 @@ export const updateCall = async (callData: UpdateCallRequest) => {
184160
};
185161

186162
const response = await updateCallApi.post<SaveCallResult>(data);
187-
163+
188164
// Invalidate cache after successful mutation
189165
try {
190166
cacheManager.remove('/Calls/GetActiveCalls');
191167
} catch (error) {
192168
// Silently handle cache removal errors
193169
console.warn('Failed to invalidate calls cache:', error);
194170
}
195-
171+
196172
return response.data;
197173
};
198174

@@ -204,14 +180,14 @@ export const closeCall = async (callData: CloseCallRequest) => {
204180
};
205181

206182
const response = await closeCallApi.put<SaveCallResult>(data);
207-
183+
208184
// Invalidate cache after successful mutation
209185
try {
210186
cacheManager.remove('/Calls/GetActiveCalls');
211187
} catch (error) {
212188
// Silently handle cache removal errors
213189
console.warn('Failed to invalidate calls cache:', error);
214190
}
215-
191+
216192
return response.data;
217193
};

src/components/maps/full-screen-location-picker.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,17 @@ const FullScreenLocationPicker: React.FC<FullScreenLocationPickerProps> = ({ ini
151151
}, [initialLocation, getUserLocation, reverseGeocode]);
152152

153153
const handleMapPress = (event: GeoJSON.Feature) => {
154-
const { coordinates } = event.geometry;
155-
const newLocation = {
156-
latitude: coordinates[1],
157-
longitude: coordinates[0],
158-
};
159-
setCurrentLocation(newLocation);
160-
setHasUserLocation(true);
161-
reverseGeocode(newLocation.latitude, newLocation.longitude);
154+
if (event.geometry.type !== 'GeometryCollection' && 'coordinates' in event.geometry) {
155+
const coords = event.geometry.coordinates as number[];
156+
const [longitude, latitude] = coords;
157+
const newLocation = {
158+
latitude,
159+
longitude,
160+
};
161+
setCurrentLocation(newLocation);
162+
setHasUserLocation(true);
163+
reverseGeocode(newLocation.latitude, newLocation.longitude);
164+
}
162165
};
163166

164167
const handleConfirmLocation = () => {

src/components/maps/location-picker.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import { Text } from '@/components/ui/text';
1111
import { Env } from '@/lib/env';
1212

1313
// Ensure Mapbox access token is set before using any Mapbox components
14-
Mapbox.setAccessToken(Env.UNIT_MAPBOX_PUBKEY);
14+
if (!Env.UNIT_MAPBOX_PUBKEY) {
15+
console.error('Mapbox access token is not configured. Please set UNIT_MAPBOX_PUBKEY in your environment.');
16+
} else {
17+
Mapbox.setAccessToken(Env.UNIT_MAPBOX_PUBKEY);
18+
}
1519

1620
// Default location (center of USA) used when user location is unavailable
1721
const DEFAULT_LOCATION = {
@@ -56,7 +60,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ initialLocation, onLoca
5660
}
5761

5862
// Create a timeout promise with cleanup
59-
let timeoutId: NodeJS.Timeout;
63+
let timeoutId: ReturnType<typeof setTimeout> | undefined;
6064
const timeoutPromise = new Promise<never>((_, reject) => {
6165
timeoutId = setTimeout(() => reject(new Error('Location timeout')), LOCATION_TIMEOUT);
6266
});
@@ -70,7 +74,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ initialLocation, onLoca
7074
]);
7175

7276
// Clear timeout if location resolved first
73-
clearTimeout(timeoutId);
77+
if (timeoutId !== undefined) clearTimeout(timeoutId);
7478

7579
if (!isMountedRef.current) return;
7680

@@ -121,11 +125,12 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ initialLocation, onLoca
121125
};
122126
}, [initialLocation, getUserLocation]);
123127

124-
const handleMapPress = (event: any) => {
125-
const { coordinates } = event.geometry;
128+
const handleMapPress = (event: GeoJSON.Feature) => {
129+
const geometry = event.geometry as GeoJSON.Point;
130+
const [longitude, latitude] = geometry.coordinates;
126131
const newLocation = {
127-
latitude: coordinates[1],
128-
longitude: coordinates[0],
132+
latitude,
133+
longitude,
129134
};
130135
setCurrentLocation(newLocation);
131136
setHasUserLocation(true);
@@ -140,15 +145,15 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ initialLocation, onLoca
140145
<Mapbox.MapView ref={mapRef} style={styles.map} logoEnabled={false} attributionEnabled={false} compassEnabled={true} zoomEnabled={true} rotateEnabled={true} onPress={handleMapPress}>
141146
<Mapbox.Camera ref={cameraRef} zoomLevel={hasUserLocation ? 15 : 4} centerCoordinate={[currentLocation.longitude, currentLocation.latitude]} animationMode="flyTo" animationDuration={1000} />
142147
{/* Marker for the selected location */}
143-
<Mapbox.PointAnnotation id="selectedLocation" coordinate={[currentLocation.longitude, currentLocation.latitude]} title="Selected Location">
148+
<Mapbox.PointAnnotation id="selectedLocation" coordinate={[currentLocation.longitude, currentLocation.latitude]} title={t('common.selected_location')}>
144149
<Box className="items-center justify-center">
145150
<MapPinIcon size={24} color="#FF0000" />
146151
</Box>
147152
</Mapbox.PointAnnotation>
148153
</Mapbox.MapView>
149154

150155
{/* My Location button */}
151-
<TouchableOpacity style={styles.myLocationButton} onPress={getUserLocation} disabled={isLocating}>
156+
<TouchableOpacity style={styles.myLocationButton} onPress={getUserLocation} disabled={isLocating} accessibilityLabel={t('common.my_location')} accessibilityRole="button">
152157
{isLocating ? <ActivityIndicator size="small" color="#007AFF" /> : <LocateIcon size={20} color="#007AFF" />}
153158
</TouchableOpacity>
154159

src/services/callkeep.service.android.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class CallKeepService {
3131
});
3232
}
3333

34-
async startCall(_displayName: string): Promise<string> {
34+
async startCall(_roomName: string, _handle?: string): Promise<string> {
3535
logger.debug({
3636
message: 'CallKeep startCall skipped - not supported on Android',
3737
});
@@ -44,26 +44,18 @@ export class CallKeepService {
4444
});
4545
}
4646

47-
async setMuted(_muted: boolean): Promise<void> {
48-
logger.debug({
49-
message: 'CallKeep setMuted skipped - not supported on Android',
50-
});
51-
}
52-
53-
setMuteStateCallback(_callback: (muted: boolean) => void | null): void {
47+
setMuteStateCallback(_callback: ((muted: boolean) => void) | null): void {
5448
logger.debug({
5549
message: 'CallKeep setMuteStateCallback skipped - not supported on Android',
5650
});
5751
}
5852

59-
async updateCallDisplay(_displayName: string): Promise<void> {
60-
logger.debug({
61-
message: 'CallKeep updateCallDisplay skipped - not supported on Android',
62-
});
53+
isCallActiveNow(): boolean {
54+
return false;
6355
}
6456

65-
isCallActive(): boolean {
66-
return false;
57+
getCurrentCallUUID(): string | null {
58+
return null;
6759
}
6860

6961
async cleanup(): Promise<void> {

src/services/callkeep.service.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Platform } from 'react-native';
2+
3+
import { callKeepService as androidCallKeepService } from './callkeep.service.android';
4+
import { callKeepService as iosCallKeepService } from './callkeep.service.ios';
5+
6+
// Export the appropriate platform-specific implementation
7+
export const callKeepService = Platform.OS === 'ios' ? iosCallKeepService : androidCallKeepService;
8+
9+
// Re-export types from iOS (they're the same in both)
10+
export type { CallKeepConfig } from './callkeep.service.ios';
11+
export { CallKeepService } from './callkeep.service.ios';

src/stores/calls/store.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ export const useCallsStore = create<CallsState>((set, get) => ({
3333
const callPrioritiesResponse = await getCallPriorities();
3434
const callTypesResponse = await getCallTypes();
3535
set({
36-
calls: callsResponse.Data,
37-
callPriorities: callPrioritiesResponse.Data,
38-
callTypes: callTypesResponse.Data,
36+
calls: Array.isArray(callsResponse.Data) ? callsResponse.Data : [],
37+
callPriorities: Array.isArray(callPrioritiesResponse.Data) ? callPrioritiesResponse.Data : [],
38+
callTypes: Array.isArray(callTypesResponse.Data) ? callTypesResponse.Data : [],
3939
isLoading: false,
4040
lastFetchedAt: Date.now(),
4141
});
@@ -44,7 +44,7 @@ export const useCallsStore = create<CallsState>((set, get) => ({
4444
set({ isLoading: true, error: null });
4545
try {
4646
const response = await getCalls();
47-
set({ calls: response.Data, isLoading: false, lastFetchedAt: Date.now() });
47+
set({ calls: Array.isArray(response.Data) ? response.Data : [], isLoading: false, lastFetchedAt: Date.now() });
4848
} catch (error) {
4949
set({ error: 'Failed to fetch calls', isLoading: false });
5050
}
@@ -53,7 +53,7 @@ export const useCallsStore = create<CallsState>((set, get) => ({
5353
set({ isLoading: true, error: null });
5454
try {
5555
const response = await getCallPriorities();
56-
set({ callPriorities: response.Data, isLoading: false });
56+
set({ callPriorities: Array.isArray(response.Data) ? response.Data : [], isLoading: false });
5757
} catch (error) {
5858
set({ error: 'Failed to fetch call priorities', isLoading: false });
5959
}
@@ -68,7 +68,7 @@ export const useCallsStore = create<CallsState>((set, get) => ({
6868
set({ isLoading: true, error: null });
6969
try {
7070
const response = await getCallTypes();
71-
set({ callTypes: response.Data, isLoading: false });
71+
set({ callTypes: Array.isArray(response.Data) ? response.Data : [], isLoading: false });
7272
} catch (error) {
7373
set({ error: 'Failed to fetch call types', isLoading: false });
7474
}

src/translations/ar.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@
316316
"go_back": "رجوع",
317317
"loading": "جاري التحميل...",
318318
"loading_address": "جاري تحميل العنوان...",
319+
"my_location": "موقعي",
319320
"next": "التالي",
320321
"noActiveUnit": "لم يتم تعيين وحدة نشطة",
321322
"noActiveUnitDescription": "يرجى تعيين وحدة نشطة من صفحة الإعدادات للوصول إلى عناصر التحكم في الحالة",
@@ -335,6 +336,7 @@
335336
"route": "مسار",
336337
"save": "حفظ",
337338
"search": "بحث...",
339+
"selected_location": "الموقع المحدد",
338340
"set_location": "تعيين الموقع",
339341
"share": "مشاركة",
340342
"step": "خطوة",

src/translations/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@
316316
"go_back": "Go Back",
317317
"loading": "Loading...",
318318
"loading_address": "Loading address...",
319+
"my_location": "My Location",
319320
"next": "Next",
320321
"noActiveUnit": "No Active Unit Set",
321322
"noActiveUnitDescription": "Please set an active unit from the settings page to access status controls",
@@ -335,6 +336,7 @@
335336
"route": "Route",
336337
"save": "Save",
337338
"search": "Search...",
339+
"selected_location": "Selected Location",
338340
"set_location": "Set Location",
339341
"share": "Share",
340342
"step": "Step",

src/translations/es.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@
316316
"go_back": "Volver",
317317
"loading": "Cargando...",
318318
"loading_address": "Cargando dirección...",
319+
"my_location": "Mi ubicación",
319320
"next": "Siguiente",
320321
"noActiveUnit": "No hay unidad activa establecida",
321322
"noActiveUnitDescription": "Por favor establezca una unidad activa desde la página de configuración para acceder a los controles de estado",
@@ -335,6 +336,7 @@
335336
"route": "Ruta",
336337
"save": "Guardar",
337338
"search": "Buscar...",
339+
"selected_location": "Ubicación seleccionada",
338340
"set_location": "Establecer ubicación",
339341
"share": "Compartir",
340342
"step": "Paso",

0 commit comments

Comments
 (0)