diff --git a/src/Utils.js b/src/Utils.js index 7edbee4..483f268 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -13,6 +13,16 @@ export function showGeneralMessage(message) { Alert.alert(strings.messages.titleMessage, message); } +export function displayValue(obj, key) { + if (obj && key) { + if (key in obj) { + return obj[key]; + } + } + + return strings.messages.empty; +} + export function logStringifyPretty(obj, title) { if (title) { console.log(title, JSON.stringify(obj, null, '\t')); diff --git a/src/assets/network-wired-solid.png b/src/assets/network-wired-solid.png new file mode 100644 index 0000000..8ab2d39 Binary files /dev/null and b/src/assets/network-wired-solid.png differ diff --git a/src/localization/LocalizationStrings.js b/src/localization/LocalizationStrings.js index 3e72757..2d636b9 100644 --- a/src/localization/LocalizationStrings.js +++ b/src/localization/LocalizationStrings.js @@ -20,15 +20,16 @@ export const strings = new LocalizedStrings({ missingEndpoints: 'System is not set up correct - missing configuration information.', samePassword: 'Password is the same as old password.', titleDashboard: 'Dashboard', - titleSignIn: 'Sign In Error', - titleSystemSetup: 'System Setup Error', + titleDeviceDetails: 'Device Error', titleDeviceList: 'Devices Error', titleForgotPassword: 'Forgot Password Error', + titleMfa: 'Multi-Factor Authentication Error', titleNetwork: 'Network Error', titleProfile: 'Profile Error', titleResetPassword: 'Reset Password Error', + titleSignIn: 'Sign In Error', titleSms: 'SMS Error', - titleMfa: 'Multi-Factor Authentication Error', + titleSystemSetup: 'System Setup Error', titleUpdate: 'Update Error', token: 'Credentials no longer valid, please sign-in again.', unknown: 'Unknown error.', @@ -85,6 +86,7 @@ export const strings = new LocalizedStrings({ submit: 'Submit', termsConditions: 'Terms & Conditions', update: 'Update', + unpause: 'Unpause', validate: 'Validate', verify: 'Verify', }, @@ -134,8 +136,11 @@ export const strings = new LocalizedStrings({ wiredClients: 'Wired Clients', }, deviceDetails: { + connected: 'Connected', connectionDetails: 'Connection Details', connectionType: 'Connection Type', + connectionTypeWifi: 'WiFi ({0})', + connectionTypeWired: 'Wired ({0})', description: 'Description', deviceDetails: 'Device Details', ipAddress: 'IP Address', diff --git a/src/screens/DeviceDetails.js b/src/screens/DeviceDetails.js index 427536b..021599a 100644 --- a/src/screens/DeviceDetails.js +++ b/src/screens/DeviceDetails.js @@ -13,7 +13,7 @@ import { import { StyleSheet, SafeAreaView, ScrollView, View, Text } from 'react-native'; import { subscriberDevicesApi, handleApiError } from '../api/apiHandler'; import { useFocusEffect } from '@react-navigation/native'; -import { showGeneralError } from '../Utils'; +import { showGeneralError, displayValue } from '../Utils'; import AccordionSection from '../components/AccordionSection'; import ButtonStyled from '../components/ButtonStyled'; import ImageWithBadge from '../components/ImageWithBadge'; @@ -44,12 +44,13 @@ const DeviceDetails = props => { const getSubsciberDevice = async (accessPointToQuery, clientToQuery) => { if (!subscriberDevicesApi) { + // This is expected to be temporary return; } try { if (!accessPointToQuery || !clientToQuery) { - showGeneralError(strings.errors.titleNetwork, strings.errors.internal); + showGeneralError(strings.errors.titleDeviceDetails, strings.errors.internal); return; } @@ -61,24 +62,22 @@ const DeviceDetails = props => { const response = await subscriberDevicesApi.getSubscriberDevices(accessPointToQuery.id); console.log(response.data); - if (response && response.data) { - const searchResult = response.data.devices.find( - deviceTemp => deviceTemp.macAddress === clientToQuery.macAddress, - ); - if (searchResult) { - setDevice(searchResult); - } else { - // List changed, so clear the current access point - setDevice(null); - showGeneralError(strings.errors.titleNetwork, strings.errors.noSubscriberDevice); - } - } else { + if (!response || !response.data || !response.data.devices) { console.error('Invalid response from getSubsciberDevice'); - showGeneralError(strings.errors.titleNetwork, strings.errors.invalidResponse); + showGeneralError(strings.errors.titleDeviceDetails, strings.errors.invalidResponse); + return; + } + + const foundDevice = response.data.devices.find(deviceTemp => deviceTemp.macAddress === clientToQuery.macAddress); + if (foundDevice) { + setDevice(foundDevice); + } else { + setDevice(null); + showGeneralError(strings.errors.titleDeviceDetails, strings.errors.noSubscriberDevice); } } catch (error) { - handleApiError(strings.errors.titleNetwork, error); + handleApiError(strings.errors.titleDeviceDetails, error); } finally { setDeviceLoading(false); } @@ -86,7 +85,7 @@ const DeviceDetails = props => { const updateDeviceValue = jsonObject => { if (jsonObject) { - // We are looping, but really only expect one + // Loop though all key/values, but really only expect one pair in the current flow for (const [key, value] of Object.entries(jsonObject)) { updateSubsciberDevice(accessPoint, client, key, value); } @@ -95,81 +94,113 @@ const DeviceDetails = props => { const updateSubsciberDevice = async (accessPointToUpdate, clientToUpdate, keyToUpdate, valueToUpdate) => { if (!subscriberDevicesApi) { + // This is expected to be temporary return; } try { if (!accessPointToUpdate || !clientToUpdate || !keyToUpdate || !valueToUpdate) { - showGeneralError(strings.errors.titleNetwork, strings.errors.internal); + showGeneralError(strings.errors.titleDeviceDetails, strings.errors.internal); return; } // Get the most current subscriber devices, we want to be as current as possible to ensure we have the latest // values before updating the new information const responseGet = await subscriberDevicesApi.getSubscriberDevices(accessPointToUpdate.id); - if (responseGet && responseGet.data) { - let subscriberDevices = responseGet.data.devices; - let deviceToUpdate = subscriberDevices.find(deviceTemp => deviceTemp.macAddress === clientToUpdate.macAddress); - - // Update the value - deviceToUpdate[keyToUpdate] = valueToUpdate; - - const responseModify = await subscriberDevicesApi.get.modifySubscriberDevices( - accessPointToUpdate.id, - false, - subscriberDevices, - ); - console.log(responseModify.data); - if (responseModify && responseModify.data) { - // Updated - no need to do anyting - } else { - console.error('Invalid response from modifySubscriberDevices'); - showGeneralError(strings.errors.titleNetwork, strings.errors.invalidResponse); - } - } else { - console.error('Invalid response from getSubscriberDevices'); - showGeneralError(strings.errors.titleNetwork, strings.errors.invalidResponse); + if (!responseGet || !responseGet.data || !responseGet.data.devices) { + console.error('Invalid response from getSubsciberDevice'); + showGeneralError(strings.errors.titleDeviceDetails, strings.errors.invalidResponse); + return; } + + let subscriberDevices = responseGet.data.devices; + let deviceToUpdate = subscriberDevices.find(deviceTemp => deviceTemp.macAddress === clientToUpdate.macAddress); + + // Update the value for the key (which will update the list as well) + deviceToUpdate[keyToUpdate] = valueToUpdate; + + const responseModify = await subscriberDevicesApi.get.modifySubscriberDevices( + accessPointToUpdate.id, + false, + subscriberDevices, + ); + console.log(responseModify.data); + + if (!responseModify || !responseModify.data) { + console.error('Invalid response from modifySubscriberDevices'); + showGeneralError(strings.errors.titleDeviceDetails, strings.errors.invalidResponse); + } + + // TODO: Verify the response code once API has been implemented + // Do nothing if everything work as expected } catch (error) { - handleApiError(strings.errors.titleNetwork, error); + handleApiError(strings.errors.titleDeviceDetails, error); } }; - const getClientIcon = () => { + const getDeviceIcon = () => { + // TODO: Handle proper icon based on device type return require('../assets/laptop-solid.png'); }; - const getClientBadgeIcon = () => { - return require('../assets/wifi-solid.png'); + const getDeviceBadgeIcon = () => { + if ('ssid' in client) { + return require('../assets/wifi-solid.png'); + } else { + return require('../assets/network-wired-solid.png'); + } }; - const getClientStatusColor = () => { - // Random choice for the moment, until the actual device parsing is implemented - let choice = Math.floor(Math.random() * 10) % 3; + const getDeviceBadgeStatusColor = () => { + if ('ssid' in client) { + const rssi = client.rssi; - switch (choice) { - case 2: + // Handle WIFI status + // TODO: Verify this + if (rssi <= -80) { return errorColor; - - case 1: + } else if (rssi > -80 && rssi <= -50) { return warnColor; - - default: - case 0: + } else if (rssi > -50 && rssi < 0) { return okColor; + } else { + return errorColor; + } + } else { + // Wired client + // TODO: Check to see if there is more to look at here + return okColor; } }; const getClientName = () => { - return client ? client.name : strings.messages.empty; + displayValue(client, 'name'); }; - const onPausePress = async () => { - // Handle pause + const onPauseUnpauseButtonLabel = () => { + if (device && !device.suspended) { + return strings.buttons.unpause; + } + + return strings.buttons.pause; + }; + + const onPauseUnpausePress = async () => { + if (device) { + // Swap the current suspend state + updateDeviceValue({ suspended: !device.suspended }); + } else { + showGeneralError(strings.errors.titleDeviceDetails, strings.errors.invalidResponse); + } }; const getConnectionType = () => { - return device ? device.name : strings.messages.empty; + // TODO: get proper connection type + if ('ssid' in client) { + return strings.formatString(strings.deviceDetails.connectionTypeWifi, displayValue(client, 'ssid')); + } else { + return strings.formatString(strings.deviceDetails.connectionTypeWired, displayValue(client, 'ssid')); + } }; // Styles @@ -207,19 +238,19 @@ const DeviceDetails = props => { {getClientName()} @@ -228,7 +259,11 @@ const DeviceDetails = props => { title={strings.deviceDetails.connectionDetails} disableAccordion={true} isLoading={deviceLoading}> - + @@ -237,44 +272,36 @@ const DeviceDetails = props => { title={strings.deviceDetails.deviceDetails} disableAccordion={true} isLoading={deviceLoading}> - + - +