Skip to content

Commit c6c8a38

Browse files
authored
Merge pull request #142 from Resgrid/develop
CU-868f1731u Working on setting the active call from detail, build fi…
2 parents b138079 + 586f38f commit c6c8a38

File tree

15 files changed

+1063
-35
lines changed

15 files changed

+1063
-35
lines changed

app.config.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import type { ConfigContext, ExpoConfig } from '@expo/config';
33

44
import { ClientEnv, Env } from './env';
5+
const packageJSON = require('./package.json');
56

67
export default ({ config }: ConfigContext): ExpoConfig => ({
78
...config,
@@ -10,7 +11,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
1011
owner: Env.EXPO_ACCOUNT_OWNER,
1112
scheme: Env.SCHEME,
1213
slug: 'resgrid-unit',
13-
version: Env.VERSION.toString(),
14+
version: packageJSON.version,
1415
orientation: 'default',
1516
icon: './assets/icon.png',
1617
userInterfaceStyle: 'automatic',
@@ -20,6 +21,8 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
2021
},
2122
assetBundlePatterns: ['**/*'],
2223
ios: {
24+
version: packageJSON.version,
25+
buildNumber: packageJSON.version,
2326
supportsTablet: true,
2427
bundleIdentifier: Env.BUNDLE_ID,
2528
requireFullScreen: true,
@@ -32,7 +35,8 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
3235
typedRoutes: true,
3336
},
3437
android: {
35-
versionCode: Env.ANDROID_VERSION_CODE,
38+
version: packageJSON.version,
39+
versionCode: parseInt(packageJSON.versionCode),
3640
adaptiveIcon: {
3741
foregroundImage: './assets/adaptive-icon.png',
3842
backgroundColor: '#2a7dd5',

docs/radio-selection-fix.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Radio Selection Fix for Status Bottom Sheet
2+
3+
## Issue Description
4+
The radio selection indicator in the Status Bottom Sheet was not working correctly. The radio buttons were not getting filled in to show which option was currently selected.
5+
6+
## Root Cause
7+
The issue was in the `handleCallSelect` function and RadioGroup value handling:
8+
9+
1. **Value mismatch**: The RadioGroup used `selectedCall?.CallId || ''` as its value, but when no call was selected (value "0"), the empty string didn't match the "No call selected" radio option.
10+
11+
2. **Incomplete selection handling**: The `handleCallSelect` function only handled cases where a valid call was found, but didn't handle the "No call selected" case (value "0").
12+
13+
3. **Button disabled state**: The Next button was disabled when `selectedCall` was null, preventing users from proceeding without selecting a call.
14+
15+
## Changes Made
16+
17+
### 1. Fixed handleCallSelect function
18+
```typescript
19+
const handleCallSelect = (callId: string) => {
20+
if (callId === '0') {
21+
setSelectedCall(null);
22+
} else {
23+
const call = calls.find((c) => c.CallId === callId);
24+
if (call) {
25+
setSelectedCall(call);
26+
}
27+
}
28+
};
29+
```
30+
31+
### 2. Updated RadioGroup value
32+
```typescript
33+
<RadioGroup value={selectedCall?.CallId || '0'} onChange={handleCallSelect}>
34+
```
35+
Changed from empty string `''` to `'0'` to match the "No call selected" radio option.
36+
37+
### 3. Removed Next button disabled state
38+
```typescript
39+
<Button onPress={handleNext} className="mt-4 w-full bg-blue-600">
40+
<ButtonText>{t('Next')}</ButtonText>
41+
</Button>
42+
```
43+
Removed `isDisabled={!selectedCall}` to allow proceeding without a selected call.
44+
45+
### 4. Updated second step display
46+
```typescript
47+
<Text className="mb-2 font-medium">
48+
{t('Selected Call')}: {selectedCall ? `${selectedCall.Number} - ${selectedCall.Name}` : t('calls.no_call_selected')}
49+
</Text>
50+
```
51+
Added conditional display to show "No call selected" when no call is chosen.
52+
53+
## Result
54+
- Radio selection indicators now properly show the selected state
55+
- Users can select "No call selected" option
56+
- Users can proceed to the next step with or without a call selected
57+
- The UI correctly displays the selected call or "No call selected" in the second step
58+
59+
## Testing
60+
The component should now:
61+
1. ✅ Show proper radio selection when a call is selected
62+
2. ✅ Show proper radio selection when "No call selected" is chosen
63+
3. ✅ Allow users to proceed with either selection
64+
4. ✅ Display the correct selection summary in the note step

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
"build:internal:ios": "cross-env APP_ENV=internal EXPO_NO_DOTENV=1 eas build --profile internal --platform ios",
3535
"build:internal:android": "cross-env APP_ENV=internal EXPO_NO_DOTENV=1 eas build --profile internal --platform android",
3636
"app-release": "cross-env SKIP_BRANCH_PROTECTION=true np --no-publish --no-cleanup --no-release-draft",
37-
"version": "yarn run prebuild && git add .",
3837
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
3938
"type-check": "tsc --noemit",
4039
"lint:translations": "eslint ./src/translations/ --fix --ext .json ",

src/app/call/[id].tsx

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { format } from 'date-fns';
22
import { Stack, useLocalSearchParams, useRouter } from 'expo-router';
3-
import { ClockIcon, FileTextIcon, ImageIcon, InfoIcon, PaperclipIcon, RouteIcon, UserIcon, UsersIcon } from 'lucide-react-native';
3+
import { ClockIcon, FileTextIcon, ImageIcon, InfoIcon, LoaderIcon, PaperclipIcon, RouteIcon, UserIcon, UsersIcon } from 'lucide-react-native';
44
import { useColorScheme } from 'nativewind';
55
import React, { useEffect, useState } from 'react';
66
import { useTranslation } from 'react-i18next';
@@ -22,15 +22,18 @@ import { VStack } from '@/components/ui/vstack';
2222
import { useAnalytics } from '@/hooks/use-analytics';
2323
import { logger } from '@/lib/logging';
2424
import { openMapsWithDirections } from '@/lib/navigation';
25+
import { useCoreStore } from '@/stores/app/core-store';
2526
import { useLocationStore } from '@/stores/app/location-store';
2627
import { useCallDetailStore } from '@/stores/calls/detail-store';
28+
import { useStatusBottomSheetStore } from '@/stores/status/store';
2729
import { useToastStore } from '@/stores/toast/store';
2830

2931
import { useCallDetailMenu } from '../../components/calls/call-detail-menu';
3032
import CallFilesModal from '../../components/calls/call-files-modal';
3133
import CallImagesModal from '../../components/calls/call-images-modal';
3234
import CallNotesModal from '../../components/calls/call-notes-modal';
3335
import { CloseCallBottomSheet } from '../../components/calls/close-call-bottom-sheet';
36+
import { StatusBottomSheet } from '../../components/status/status-bottom-sheet';
3437

3538
export default function CallDetail() {
3639
const { id } = useLocalSearchParams();
@@ -48,10 +51,13 @@ export default function CallDetail() {
4851
longitude: null,
4952
});
5053
const { call, callExtraData, callPriority, isLoading, error, fetchCallDetail, reset } = useCallDetailStore();
54+
const { activeCall, activeStatuses } = useCoreStore();
55+
const { setIsOpen: setStatusBottomSheetOpen, setSelectedCall } = useStatusBottomSheetStore();
5156
const [isNotesModalOpen, setIsNotesModalOpen] = useState(false);
5257
const [isImagesModalOpen, setIsImagesModalOpen] = useState(false);
5358
const [isFilesModalOpen, setIsFilesModalOpen] = useState(false);
5459
const [isCloseCallModalOpen, setIsCloseCallModalOpen] = useState(false);
60+
const [isSettingActive, setIsSettingActive] = useState(false);
5561
const showToast = useToastStore((state) => state.showToast);
5662

5763
const { colorScheme } = useColorScheme();
@@ -88,6 +94,37 @@ export default function CallDetail() {
8894
setIsCloseCallModalOpen(true);
8995
};
9096

97+
const handleSetActive = async () => {
98+
if (!call) return;
99+
100+
setIsSettingActive(true);
101+
102+
try {
103+
// Set this call as the active call in the core store
104+
await useCoreStore.getState().setActiveCall(call.CallId);
105+
106+
// Find a "Responding" or "En Route" status from the available statuses
107+
const respondingStatus = activeStatuses?.Statuses.find(
108+
(status) => status.Text.toLowerCase().includes('responding') || status.Text.toLowerCase().includes('en route') || status.Text.toLowerCase().includes('enroute')
109+
);
110+
111+
// Pre-select the current call and open the status bottom sheet
112+
setSelectedCall(call);
113+
setStatusBottomSheetOpen(true, respondingStatus || activeStatuses?.Statuses[0]);
114+
115+
// Show success message
116+
showToast('success', t('call_detail.set_active_success'));
117+
} catch (error) {
118+
logger.error({
119+
message: 'Failed to set call as active',
120+
context: { error, callId: call.CallId },
121+
});
122+
showToast('error', t('call_detail.set_active_error'));
123+
} finally {
124+
setIsSettingActive(false);
125+
}
126+
};
127+
91128
// Initialize the call detail menu hook
92129
const { HeaderRightMenu, CallDetailActionSheet } = useCallDetailMenu({
93130
onEditCall: handleEditCall,
@@ -446,10 +483,17 @@ export default function CallDetail() {
446483
<ScrollView className={`size-full w-full flex-1 ${colorScheme === 'dark' ? 'bg-neutral-950' : 'bg-neutral-50'}`}>
447484
{/* Header */}
448485
<Box className={`p-4 shadow-sm ${colorScheme === 'dark' ? 'bg-neutral-900' : 'bg-neutral-100'}`}>
449-
<HStack className="mb-2 items-center">
486+
<HStack className="mb-2 items-center justify-between">
450487
<Heading size="md">
451488
{call.Name} ({call.Number})
452489
</Heading>
490+
{/* Show "Set Active" button if this call is not the active call */}
491+
{activeCall?.CallId !== call.CallId && (
492+
<Button variant="solid" size="sm" onPress={handleSetActive} disabled={isSettingActive} className={`${isSettingActive ? 'bg-primary-400 opacity-80' : 'bg-primary-500'} shadow-lg`}>
493+
{isSettingActive && <ButtonIcon as={LoaderIcon} className="mr-1 animate-spin text-white" />}
494+
<ButtonText className="font-medium text-white">{isSettingActive ? t('call_detail.setting_active') : t('call_detail.set_active')}</ButtonText>
495+
</Button>
496+
)}
453497
</HStack>
454498
<VStack className="space-y-1">
455499
<Box style={{ height: 80 }}>
@@ -548,6 +592,9 @@ export default function CallDetail() {
548592
{/* Close Call Bottom Sheet */}
549593
<CloseCallBottomSheet isOpen={isCloseCallModalOpen} onClose={() => setIsCloseCallModalOpen(false)} callId={callId} />
550594

595+
{/* Status Bottom Sheet */}
596+
<StatusBottomSheet />
597+
551598
{/* Call Detail Menu ActionSheet */}
552599
<CallDetailActionSheet />
553600
</>

0 commit comments

Comments
 (0)