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);
}