Feature/callpage #18
11 changed files with 3757 additions and 5753 deletions
8
app.json
8
app.json
|
|
@ -23,13 +23,9 @@
|
||||||
},
|
},
|
||||||
"package": "com.anonymous.testapplication"
|
"package": "com.anonymous.testapplication"
|
||||||
},
|
},
|
||||||
// "web": {
|
|
||||||
// "bundler": "metro",
|
|
||||||
// "output": "static",
|
|
||||||
// "favicon": "./assets/images/favicon.png"
|
|
||||||
// },
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"expo-router"
|
"expo-router",
|
||||||
|
"expo-font"
|
||||||
],
|
],
|
||||||
"experiments": {
|
"experiments": {
|
||||||
"typedRoutes": true
|
"typedRoutes": true
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,20 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { router, Stack } from 'expo-router';
|
import { Slot, router, Stack } from 'expo-router';
|
||||||
|
import { WebSocketProvider } from '../contexts/WebSocketContext';
|
||||||
|
|
||||||
export const unstable_settings = {
|
export const unstable_settings = {
|
||||||
// Ensure any route can link back to `/`
|
|
||||||
initialRouteName: 'login',
|
initialRouteName: 'login',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
router.replace('/login');
|
router.replace('/login');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack
|
<WebSocketProvider>
|
||||||
screenOptions={{
|
<Slot />
|
||||||
headerShown: false
|
</WebSocketProvider>
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack.Screen name="login" />
|
|
||||||
<Stack.Screen name="register" />
|
|
||||||
<Stack.Screen name="explore" />
|
|
||||||
<Stack.Screen name="incidents" />
|
|
||||||
<Stack.Screen name="landing" />
|
|
||||||
</Stack>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +114,7 @@ export default function Incidents() {
|
||||||
style={{
|
style={{
|
||||||
color: selectedDepartmentColorPicker(selectedDepartment?.type),
|
color: selectedDepartmentColorPicker(selectedDepartment?.type),
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
fontSize: '14px'
|
fontSize: 14
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{selectedDepartment?.deptAbv}
|
{selectedDepartment?.deptAbv}
|
||||||
|
|
@ -177,7 +177,7 @@ export default function Incidents() {
|
||||||
item?.type
|
item?.type
|
||||||
),
|
),
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
fontSize: '16px'
|
fontSize: 16
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item?.dept}
|
{item?.dept}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
import { useCallFeed } from '../hooks/useCallFeed';
|
import { useCallFeed } from '../hooks/useCallFeed';
|
||||||
import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native';
|
import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native';
|
||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
|
|
@ -10,6 +11,9 @@ import {
|
||||||
PageHeader,
|
PageHeader,
|
||||||
PageFooter,
|
PageFooter,
|
||||||
} from './generalHelpers.jsx';
|
} from './generalHelpers.jsx';
|
||||||
|
import ActionSheet from 'react-native-actions-sheet';
|
||||||
|
|
||||||
|
const DepartmentActionSheet = styled(ActionSheet)``;
|
||||||
|
|
||||||
export default function Landing() {
|
export default function Landing() {
|
||||||
const actionSheetRef = useRef(null);
|
const actionSheetRef = useRef(null);
|
||||||
|
|
@ -29,6 +33,7 @@ export default function Landing() {
|
||||||
setSelectedDepartment,
|
setSelectedDepartment,
|
||||||
updateSelectedDepartment,
|
updateSelectedDepartment,
|
||||||
selectedDepartmentColorPicker,
|
selectedDepartmentColorPicker,
|
||||||
|
deptList,
|
||||||
} = departments;
|
} = departments;
|
||||||
|
|
||||||
const { Incident, Address, Person, Response } = callDetails;
|
const { Incident, Address, Person, Response } = callDetails;
|
||||||
|
|
@ -188,7 +193,7 @@ export default function Landing() {
|
||||||
style={{
|
style={{
|
||||||
color: selectedDepartmentColorPicker(selectedDepartment?.type),
|
color: selectedDepartmentColorPicker(selectedDepartment?.type),
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
fontSize: '14px'
|
fontSize: '14'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{selectedDepartment?.deptAbv}
|
{selectedDepartment?.deptAbv}
|
||||||
|
|
@ -835,7 +840,7 @@ export default function Landing() {
|
||||||
item?.type
|
item?.type
|
||||||
),
|
),
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
fontSize: '16px'
|
fontSize: '16'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item?.dept}
|
{item?.dept}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { View } from 'react-native';
|
import { View, Text } from 'react-native';
|
||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
import { useFormik } from 'formik';
|
import { useFormik } from 'formik';
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||||
|
|
@ -21,8 +21,11 @@ import {
|
||||||
TextLinkContent,
|
TextLinkContent,
|
||||||
LoginTextInput
|
LoginTextInput
|
||||||
} from './generalHelpers.jsx';
|
} from './generalHelpers.jsx';
|
||||||
|
import { useWebSocketContext } from '../hooks/useWebSocketContext';
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
|
const { isConnected, lastMessage, sendMessage } = useWebSocketContext();
|
||||||
|
|
||||||
const [hidePassword, setHidePassword] = useState(true);
|
const [hidePassword, setHidePassword] = useState(true);
|
||||||
const [loginButtonDisabled, setLoginButtonDisabled] = useState(true);
|
const [loginButtonDisabled, setLoginButtonDisabled] = useState(true);
|
||||||
const [auth, setAuth] = useState(false);
|
const [auth, setAuth] = useState(false);
|
||||||
|
|
@ -110,14 +113,20 @@ export default function Login() {
|
||||||
<Link href='./register'>
|
<Link href='./register'>
|
||||||
<TextLinkContent>Register</TextLinkContent>
|
<TextLinkContent>Register</TextLinkContent>
|
||||||
</Link>
|
</Link>
|
||||||
|
</ExtraView>
|
||||||
|
</StyledFormArea>
|
||||||
|
<Line />
|
||||||
|
<Text>Temporary Area:</Text>
|
||||||
|
<View>
|
||||||
<Link href='./incidents'>
|
<Link href='./incidents'>
|
||||||
<TextLinkContent>Incidents</TextLinkContent>
|
<TextLinkContent>Incidents</TextLinkContent>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href='./landing'>
|
<Link href='./landing'>
|
||||||
<TextLinkContent>Landing</TextLinkContent>
|
<TextLinkContent>Landing</TextLinkContent>
|
||||||
</Link>
|
</Link>
|
||||||
</ExtraView>
|
</View>
|
||||||
</StyledFormArea>
|
<Line />
|
||||||
|
<Text>Socket connected: {isConnected ? '✅ Yes' : '❌ No'}</Text>
|
||||||
</InnerContainer>
|
</InnerContainer>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
||||||
50
contexts/WebSocketContext.js
Normal file
50
contexts/WebSocketContext.js
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import React, { createContext, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
export const WebSocketContext = createContext(null);
|
||||||
|
|
||||||
|
export const WebSocketProvider = ({ children }) => {
|
||||||
|
const ws = useRef(null);
|
||||||
|
const [isConnected, setIsConnected] = useState(false);
|
||||||
|
const [lastMessage, setLastMessage] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
ws.current = new WebSocket('wss://your-websocket-server.com');
|
||||||
|
|
||||||
|
ws.current.onopen = () => {
|
||||||
|
console.log('✅ WebSocket connected');
|
||||||
|
setIsConnected(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.current.onmessage = (e) => {
|
||||||
|
console.log('📩 Message received:', e.data);
|
||||||
|
setLastMessage(e.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.current.onerror = (e) => {
|
||||||
|
console.error('❌ WebSocket error:', e.message);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.current.onclose = (e) => {
|
||||||
|
console.log('🔌 WebSocket closed:', e.code, e.reason);
|
||||||
|
setIsConnected(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
ws.current?.close();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const sendMessage = (msg) => {
|
||||||
|
if (ws.current?.readyState === WebSocket.OPEN) {
|
||||||
|
ws.current.send(JSON.stringify(msg));
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ WebSocket is not open. Message not sent.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WebSocketContext.Provider value={{ sendMessage, lastMessage, isConnected }}>
|
||||||
|
{children}
|
||||||
|
</WebSocketContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
1
hooks/useWebSocketContext/index.js
Normal file
1
hooks/useWebSocketContext/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { useWebSocketContext } from './useWebSocketContext';
|
||||||
4
hooks/useWebSocketContext/useWebSocketContext.js
Normal file
4
hooks/useWebSocketContext/useWebSocketContext.js
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { WebSocketContext } from '../../contexts/WebSocketContext';
|
||||||
|
|
||||||
|
export const useWebSocketContext = () => useContext(WebSocketContext);
|
||||||
9330
package-lock.json
generated
9330
package-lock.json
generated
File diff suppressed because it is too large
Load diff
40
package.json
40
package.json
|
|
@ -17,38 +17,38 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^14.0.2",
|
"@expo/vector-icons": "^14.0.2",
|
||||||
"@react-navigation/native": "^6.0.2",
|
"@react-navigation/native": "^6.0.2",
|
||||||
"expo": "~51.0.24",
|
"expo": "^52.0.46",
|
||||||
"expo-constants": "~16.0.2",
|
"expo-constants": "~17.0.8",
|
||||||
"expo-font": "~12.0.9",
|
"expo-font": "~13.0.4",
|
||||||
"expo-linking": "~6.3.1",
|
"expo-linking": "~7.0.5",
|
||||||
"expo-router": "~3.5.20",
|
"expo-router": "~4.0.20",
|
||||||
"expo-splash-screen": "~0.27.5",
|
"expo-splash-screen": "~0.29.24",
|
||||||
"expo-status-bar": "~1.12.1",
|
"expo-status-bar": "~2.0.1",
|
||||||
"expo-system-ui": "~3.0.7",
|
"expo-system-ui": "~4.0.9",
|
||||||
"expo-web-browser": "~13.0.3",
|
"expo-web-browser": "~14.0.2",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"healthicons-react-native": "^3.0.0",
|
"healthicons-react-native": "^3.0.0",
|
||||||
"react": "18.2.0",
|
"react": "18.3.1",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.3.1",
|
||||||
"react-native": "0.74.3",
|
"react-native": "0.76.9",
|
||||||
"react-native-actions-sheet": "^0.9.7",
|
"react-native-actions-sheet": "^0.9.7",
|
||||||
"react-native-dropdown-picker": "^5.4.6",
|
"react-native-dropdown-picker": "^5.4.6",
|
||||||
"react-native-gesture-handler": "~2.16.1",
|
"react-native-gesture-handler": "~2.20.2",
|
||||||
"react-native-reanimated": "~3.10.1",
|
"react-native-reanimated": "~3.16.1",
|
||||||
"react-native-safe-area-context": "4.10.5",
|
"react-native-safe-area-context": "4.12.0",
|
||||||
"react-native-screens": "3.31.1",
|
"react-native-screens": "~4.4.0",
|
||||||
"react-native-svg": "^15.7.1",
|
"react-native-svg": "15.8.0",
|
||||||
"react-native-textinput-effects": "^0.6.3",
|
"react-native-textinput-effects": "^0.6.3",
|
||||||
"react-native-web": "~0.19.10",
|
"react-native-web": "~0.19.13",
|
||||||
"styled-components": "^6.1.12"
|
"styled-components": "^6.1.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.20.0",
|
"@babel/core": "^7.20.0",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/react": "~18.2.45",
|
"@types/react": "~18.3.12",
|
||||||
"@types/react-test-renderer": "^18.0.7",
|
"@types/react-test-renderer": "^18.0.7",
|
||||||
"jest": "^29.2.1",
|
"jest": "^29.2.1",
|
||||||
"jest-expo": "~51.0.3",
|
"jest-expo": "~52.0.6",
|
||||||
"react-test-renderer": "18.2.0",
|
"react-test-renderer": "18.2.0",
|
||||||
"typescript": "~5.3.3"
|
"typescript": "~5.3.3"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,5 @@
|
||||||
"**/*.jsx",
|
"**/*.jsx",
|
||||||
".expo/types/**/*.ts",
|
".expo/types/**/*.ts",
|
||||||
"expo-env.d.ts"
|
"expo-env.d.ts"
|
||||||
]
|
, "contexts/WebSocketContext.js" ]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue