adding admin page

This commit is contained in:
Roland Osborne 2022-10-12 12:24:29 -07:00
parent f012b582ed
commit 50c965e794
15 changed files with 199 additions and 174 deletions

View File

@ -5,7 +5,7 @@ import { Routes, Route } from 'react-router-dom';
import { Root } from 'src/root/Root';
import { Access } from 'src/access/Access';
import { Session } from 'src/session/Session';
import { Admin } from 'src/admin/Admin';
import { Dashboard } from 'src/dashboard/Dashboard';
import { StoreContextProvider } from 'context/StoreContext';
import { UploadContextProvider } from 'context/UploadContext';
import { AppContextProvider } from 'context/AppContext';
@ -36,7 +36,8 @@ export default function App() {
<NativeRouter>
<Routes>
<Route path="/" element={ <Root /> } />
<Route path="/admin" element={ <Admin /> } />
<Route path="/admin" element={ <Access mode="admin" /> } />
<Route path="/dashboard" element={ <Dashboard /> } />
<Route path="/login" element={ <Access mode="login" /> } />
<Route path="/reset" element={ <Access mode="reset" /> } />
<Route path="/create" element={ <Access mode="create" /> } />

View File

@ -4,6 +4,7 @@ import { useAccess } from './useAccess.hook';
import { Login } from './login/Login';
import { Create } from './create/Create';
import { Reset } from './reset/Reset';
import { Admin } from './admin/Admin';
import logo from 'images/login.png';
export function Access({ mode }) {
@ -28,6 +29,9 @@ export function Access({ mode }) {
{ mode === 'reset' && (
<Reset />
)}
{ mode === 'admin' && (
<Admin />
)}
</View>
</View>
)}
@ -42,6 +46,9 @@ export function Access({ mode }) {
{ mode === 'reset' && (
<Reset />
)}
{ mode === 'admin' && (
<Admin />
)}
</View>
)}
</SafeAreaView>

View File

@ -0,0 +1,73 @@
import { ActivityIndicator, Alert, Text, TextInput, View, TouchableOpacity } from 'react-native';
import { styles } from './Admin.styled';
import Ionicons from '@expo/vector-icons/AntDesign';
import { useAdmin } from './useAdmin.hook';
export function Admin() {
const { state, actions } = useAdmin();
const admin = async () => {
try {
await actions.access();
}
catch (err) {
Alert.alert(
"Access Failed",
"Please check your server and token.",
);
}
}
return (
<View style={styles.wrapper}>
<View style={styles.container}>
<View style={styles.control}>
<TouchableOpacity onPress={actions.login}>
<Ionicons style={styles.config} name="user" size={24} color="#aaaaaa" />
</TouchableOpacity>
</View>
<Text style={styles.title}>Databag</Text>
<View style={styles.spacemid}>
<Text style={styles.header}>Admin Acess</Text>
</View>
<View style={styles.spacetop}>
<View style={styles.inputwrapper}>
<Ionicons style={styles.icon} name="database" size={18} color="#aaaaaa" />
<TextInput style={styles.inputfield} value={state.server} onChangeText={actions.setServer}
autoCorrect={false} autoCapitalize="none" placeholder="server" />
<View style={styles.space} />
</View>
<View style={styles.inputwrapper}>
<Ionicons style={styles.icon} name="key" size={18} color="#aaaaaa" />
<TextInput style={styles.inputfield} value={state.token} onChangeText={actions.setToken}
secureTextEntry={!state.plainText} autoCapitalize="none" placeholder="token"/>
<TouchableOpacity>
{ state.plainText && (
<Ionicons style={styles.icon} name="eye" size={18} color="#aaaaaa" onPress={actions.hidePass}/>
)}
{ !state.plainText && (
<Ionicons style={styles.icon} name="eyeo" size={18} color="#aaaaaa" onPress={actions.showPass}/>
)}
</TouchableOpacity>
</View>
{ state.enabled && (
<TouchableOpacity style={styles.reset} onPress={admin}>
{ state.busy && (
<ActivityIndicator size="small" color="#ffffff" />
)}
{ !state.busy && (
<Text style={styles.resettext}>Access</Text>
)}
</TouchableOpacity>
)}
{ !state.enabled && (
<View style={styles.noreset}>
<Text style={styles.noresettext}>Access</Text>
</View>
)}
</View>
</View>
</View>
);
}

View File

@ -72,7 +72,7 @@ export const styles = StyleSheet.create({
textAlign: 'center',
padding: 8,
},
login: {
reset: {
marginTop: 16,
display: 'flex',
alignItems: 'center',
@ -82,10 +82,10 @@ export const styles = StyleSheet.create({
backgroundColor: Colors.primary,
borderRadius: 4,
},
logintext: {
resettext: {
color: Colors.formFocus,
},
nologin: {
noreset: {
marginTop: 16,
display: 'flex',
alignItems: 'center',
@ -96,8 +96,18 @@ export const styles = StyleSheet.create({
borderColor: Colors.divider,
borderWidth: 1,
},
noresettext: {
color: Colors.disabled,
},
login: {
marginTop: 16,
},
logintext: {
fontColor: 'yellow',
},
nologintext: {
color: Colors.disabled,
},
})

View File

@ -0,0 +1,83 @@
import { useState, useEffect, useContext } from 'react';
import { useWindowDimensions } from 'react-native';
import { useNavigate } from 'react-router-dom';
import { AppContext } from 'context/AppContext';
import { getNodeStatus } from 'api/getNodeStatus';
import { setNodeStatus } from 'api/setNodeStatus';
import { getNodeConfig } from 'api/getNodeConfig';
export function useAdmin() {
const navigate = useNavigate();
const app = useContext(AppContext);
const [state, setState] = useState({
busy: false,
enabled: false,
server: null,
token: null,
plainText: false,
});
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
const checkStatus = async () => {
try {
updateState({ unclaimed: status });
}
catch (err) {
console.log("failed to check node status");
}
};
useEffect(() => {
if (state.token && state.server && !state.enabled) {
updateState({ enabled: true });
}
if ((!state.token || !state.server) && state.enabled) {
updateState({ enabled: false });
}
}, [state.server, state.token]);
const actions = {
setServer: (server) => {
updateState({ server });
},
setToken: (token) => {
updateState({ token });
},
login: () => {
navigate('/login');
},
showPass: () => {
updateState({ plainText: true });
},
hidePass: () => {
updateState({ plainText: false });
},
access: async () => {
if (!state.busy) {
try {
updateState({ busy: true });
const unclaimed = await getNodeStatus(state.server);
if (unclaimed) {
await setNodeStatus(state.server, state.token);
}
const config = await getNodeConfig(state.server, state.token);
updateState({ busy: false });
navigate('/dashboard');
}
catch (err) {
console.log(err);
updateState({ busy: false });
throw new Error("access failed");
}
}
}
};
return { state, actions };
}

View File

@ -1,44 +0,0 @@
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() {
const { state, actions } = useAdmin();
return (
<View style={styles.wrapper}>
<SafeAreaView>
{ state.split === true && (
<View style={styles.container}>
<View style={styles.paddedPane}>
<Image style={styles.splash} source={logo} />
</View>
<View style={styles.pane}>
{ state.token == null && (
<Prompt login={actions.login} />
)}
{ state.token != null && (
<Dashboard token={state.token} config={state.config} logout={actions.logout} />
)}
</View>
</View>
)}
{ state.split === false && (
<View style={styles.container}>
{ state.token == null && (
<Prompt login={actions.login} />
)}
{ state.token != null && (
<Dashboard token={state.token} config={state.config} logout={actions.logout} />
)}
</View>
)}
</SafeAreaView>
</View>
);
}

View File

@ -1,30 +0,0 @@
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,
},
});

View File

@ -1,34 +0,0 @@
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 (
<View style={styles.wrapper}>
<View style={styles.container}>
<View style={styles.control}>
<TouchableOpacity onPress={actions.login}>
<Ionicons style={styles.config} name="user" size={24} color="#aaaaaa" />
</TouchableOpacity>
</View>
</View>
</View>
);
}

View File

@ -1,25 +0,0 @@
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 };
}

View File

@ -1,29 +0,0 @@
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 };
}

View File

@ -1,3 +1,4 @@
export function Dashboard() {
return <></>
}

View File

@ -18,7 +18,7 @@ export function AddMember({ members, item, setCard, clearCard }) {
};
return (
<View style={styles.container}>
<TouchableOpacity activeOpacity={1} style={styles.container} onPress={() => setMember(!state.member)}>
<Logo src={state.logo} width={32} height={32} radius={6} />
<View style={styles.detail}>
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ state.name }</Text>
@ -26,7 +26,7 @@ export function AddMember({ members, item, setCard, clearCard }) {
</View>
<Switch style={styles.switch} trackColor={styles.track}
value={state.member} onValueChange={setMember} />
</View>
</TouchableOpacity>
);
}

View File

@ -118,7 +118,8 @@ export function AddTopic() {
renderItem={renderAsset}
/>
)}
<TextInput style={styles.input} value={state.message} onChangeText={actions.setMessage} ref={message}
<TextInput style={{ ...styles.input, color: state.color, fontSize: state.textSize }} value={state.message} onChangeText={actions.setMessage} ref={message}
placeholderTextColor={state.color} cursorColor={state.color}
onSubmitEditing={sendMessage} returnKeyType="send"
autoCapitalize="sentences" placeholder="New Message" multiline={true} />
<View style={styles.addButtons}>

View File

@ -15,6 +15,7 @@ export function useAddTopic(cardId, channelId) {
color: Colors.text,
colorSet: false,
busy: false,
textSize: 14,
});
const assetId = useRef(0);
@ -79,7 +80,17 @@ export function useAddTopic(cardId, channelId) {
updateState({ fontSize: false });
},
setFontSize: (size) => {
updateState({ size, sizeSet: true });
let textSize;
if (size === 'large') {
textSize = 18;
}
else if (size === 'small') {
textSize = 10;
}
else {
textSize = 14;
}
updateState({ size, sizeSet: true, textSize });
},
setFontColor: (color) => {
updateState({ color, colorSet: true });
@ -95,7 +106,7 @@ export function useAddTopic(cardId, channelId) {
};
await conversation.actions.addTopic(message, state.assets);
updateState({ busy: false, assets: [], message: null,
size: 'medium', sizeSet: false,
size: 'medium', sizeSet: false, textSize: 14,
color: Colors.text, colorSet: false,
});
}

View File

@ -23,7 +23,7 @@ export function MemberItem({ hostId, editable, members, item }) {
};
return (
<View style={styles.container}>
<TouchableOpacity style={styles.container} activeOpacity={1} onPress={() => setMember(!state.member)}>
<Logo src={state.logo} width={32} height={32} radius={6} />
<View style={styles.detail}>
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ state.name }</Text>
@ -36,7 +36,7 @@ export function MemberItem({ hostId, editable, members, item }) {
<Switch style={styles.switch} trackColor={styles.track}
value={state.member} onValueChange={setMember} />
)}
</View>
</TouchableOpacity>
);
}