diff --git a/app/mobile/src/admin/Admin.jsx b/app/mobile/src/admin/Admin.jsx index 599d8358..e88a75ed 100644 --- a/app/mobile/src/admin/Admin.jsx +++ b/app/mobile/src/admin/Admin.jsx @@ -1,4 +1,44 @@ +import { SafeAreaView, Image, View } from 'react-native'; +import { styles } from './Admin.styled'; +import { useAdmin } from './useAdmin.hook'; +import { Prompt } from './prompt/Prompt'; +import { Dashboard } from './dashboard/Dashboard'; +import logo from 'images/login.png'; + export function Admin() { - return <> + + const { state, actions } = useAdmin(); + + return ( + + + { state.split === true && ( + + + + + + { state.token == null && ( + + )} + { state.token != null && ( + + )} + + + )} + { state.split === false && ( + + { state.token == null && ( + + )} + { state.token != null && ( + + )} + + )} + + + ); } diff --git a/app/mobile/src/admin/Admin.styled.js b/app/mobile/src/admin/Admin.styled.js new file mode 100644 index 00000000..4b04240a --- /dev/null +++ b/app/mobile/src/admin/Admin.styled.js @@ -0,0 +1,30 @@ +import { StyleSheet } from 'react-native'; +import { Colors } from 'constants/Colors'; + +export const styles = StyleSheet.create({ + wrapper: { + backgroundColor: Colors.background, + width: '100%', + height: '100%', + }, + container: { + padding: 16, + display: 'flex', + flexDirection: 'row', + }, + splash: { + flex: 1, + width: null, + height: null, + resizeMode: 'contain', + }, + pane: { + width: '50%', + height: '100%', + }, + paddedPane: { + width: '50%', + height: '100%', + paddingRight: 16, + }, +}); diff --git a/app/mobile/src/admin/dashboard/Dashboard.jsx b/app/mobile/src/admin/dashboard/Dashboard.jsx new file mode 100644 index 00000000..d105d5d7 --- /dev/null +++ b/app/mobile/src/admin/dashboard/Dashboard.jsx @@ -0,0 +1,3 @@ +export function Dashboard() { + return <> +} diff --git a/app/mobile/src/admin/prompt/Prompt.jsx b/app/mobile/src/admin/prompt/Prompt.jsx new file mode 100644 index 00000000..660e0b94 --- /dev/null +++ b/app/mobile/src/admin/prompt/Prompt.jsx @@ -0,0 +1,34 @@ +import { ActivityIndicator, Alert, Text, TextInput, View, TouchableOpacity } from 'react-native'; +import { styles } from './Prompt.styled'; +import Ionicons from '@expo/vector-icons/AntDesign'; +import { usePrompt } from './usePrompt.hook'; + +export function Prompt({ login }) { + + const { state, actions } = usePrompt(); + + const setLogin = async () => { + try { + let config = await actions.attach(); + login(state.password, config); + } + catch(err) { + Alert.alert( + "Access Failed", + "Please check your admin token.", + ); + } + }; + + return ( + + + + + + + + + + ); +} diff --git a/app/mobile/src/admin/prompt/Prompt.styled.js b/app/mobile/src/admin/prompt/Prompt.styled.js new file mode 100644 index 00000000..7d6f7b11 --- /dev/null +++ b/app/mobile/src/admin/prompt/Prompt.styled.js @@ -0,0 +1,103 @@ +import { StyleSheet } from 'react-native'; +import { Colors } from 'constants/Colors'; + +export const styles = StyleSheet.create({ + wrapper: { + width: '100%', + height: '100%', + }, + config: { + paddingTop: 8, + }, + icon: { + padding: 8, + }, + space: { + width: 32, + }, + container: { + flexDirection: 'column', + backgroundColor: Colors.formBackground, + borderRadius: 4, + width: '100%', + height: '100%', + display: 'flex', + paddingLeft: 16, + paddingRight: 16, + }, + control: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'flex-end', + color: Colors.grey, + }, + title: { + width: '100%', + textAlign: 'center', + fontSize: 24, + color: Colors.grey, + }, + spacemid: { + flexGrow: 1, + flexDirection: 'column', + textAlign: 'center', + alignItems: 'center', + justifyContent: 'center', + width: '100%', + }, + spacetop: { + flexGrow: 1, + flexDirection: 'column', + textAlign: 'center', + alignItems: 'center', + justifyContent: 'flex-start', + width: '100%', + }, + header: { + fontSize: 32, + color: Colors.text, + }, + inputwrapper: { + display: 'flex', + flexDirection: 'row', + width: '100%', + borderRadius: 4, + borderColor: Colors.divider, + borderWidth: 1, + marginBottom: 16, + alignItems: 'center', + }, + inputfield: { + flex: 1, + textAlign: 'center', + padding: 8, + }, + login: { + marginTop: 16, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + width: 128, + height: 28, + backgroundColor: Colors.primary, + borderRadius: 4, + }, + logintext: { + color: Colors.formFocus, + }, + nologin: { + marginTop: 16, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + width: 128, + height: 28, + borderRadius: 4, + borderColor: Colors.divider, + borderWidth: 1, + }, + nologintext: { + color: Colors.disabled, + }, +}) + diff --git a/app/mobile/src/admin/prompt/usePrompt.hook.js b/app/mobile/src/admin/prompt/usePrompt.hook.js new file mode 100644 index 00000000..fe3b1118 --- /dev/null +++ b/app/mobile/src/admin/prompt/usePrompt.hook.js @@ -0,0 +1,25 @@ +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; + +export function usePrompt() { + + const navigate = useNavigate(); + + const [state, setState] = useState({ + }); + + const updateState = (value) => { + setState((s) => ({ ...s, ...value })); + } + + const actions = { + attach: () => { + }, + login: () => { + navigate('/login'); + } + }; + + return { state, actions }; +} + diff --git a/app/mobile/src/admin/useAdmin.hook.js b/app/mobile/src/admin/useAdmin.hook.js new file mode 100644 index 00000000..fb6c722e --- /dev/null +++ b/app/mobile/src/admin/useAdmin.hook.js @@ -0,0 +1,29 @@ +import { useState, useEffect } from 'react'; +import { useWindowDimensions } from 'react-native'; + +export function useAdmin() { + + const [state, setState] = useState({ + split: null, + }); + const dimensions = useWindowDimensions(); + + const updateState = (value) => { + setState((s) => ({ ...s, ...value })); + } + + useEffect(() => { + if (dimensions.width > 650) { + updateState({ split: true }); + } + else { + updateState({ split: false }); + } + }, [dimensions]); + + const actions = { + }; + + return { state, actions }; +} + diff --git a/app/mobile/src/api/getNodeConfig.js b/app/mobile/src/api/getNodeConfig.js index fea820e3..e4e65f47 100644 --- a/app/mobile/src/api/getNodeConfig.js +++ b/app/mobile/src/api/getNodeConfig.js @@ -1,7 +1,7 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil'; -export async function getNodeConfig(token) { - let config = await fetchWithTimeout(`/admin/config?token=${token}`, { method: 'GET' }); +export async function getNodeConfig(server, token) { + let config = await fetchWithTimeout(`https://${server}/admin/config?token=${token}`, { method: 'GET' }); checkResponse(config); return await config.json(); } diff --git a/app/mobile/src/api/getNodeStatus.js b/app/mobile/src/api/getNodeStatus.js index 9232bf0a..134a7596 100644 --- a/app/mobile/src/api/getNodeStatus.js +++ b/app/mobile/src/api/getNodeStatus.js @@ -1,7 +1,7 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil'; -export async function getNodeStatus() { - let status = await fetchWithTimeout(`/admin/status`, { method: 'GET' }); +export async function getNodeStatus(server) { + let status = await fetchWithTimeout(`http://${server}/admin/status`, { method: 'GET' }); checkResponse(status); return await status.json(); } diff --git a/app/mobile/src/api/setNodeStatus.js b/app/mobile/src/api/setNodeStatus.js index 2d2bc860..01dd2711 100644 --- a/app/mobile/src/api/setNodeStatus.js +++ b/app/mobile/src/api/setNodeStatus.js @@ -1,7 +1,7 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil'; -export async function setNodeStatus(token) { - let status = await fetchWithTimeout(`/admin/status?token=${token}`, { method: 'PUT' }); +export async function setNodeStatus(server, token) { + let status = await fetchWithTimeout(`http://${server}/admin/status?token=${token}`, { method: 'PUT' }); checkResponse(status); }