mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
adding admin page
This commit is contained in:
parent
f012b582ed
commit
50c965e794
@ -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" /> } />
|
||||
|
@ -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>
|
||||
|
73
app/mobile/src/access/admin/Admin.jsx
Normal file
73
app/mobile/src/access/admin/Admin.jsx
Normal 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>
|
||||
);
|
||||
}
|
@ -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,
|
||||
},
|
||||
|
||||
})
|
||||
|
83
app/mobile/src/access/admin/useAdmin.hook.js
Normal file
83
app/mobile/src/access/admin/useAdmin.hook.js
Normal 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 };
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
});
|
@ -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>
|
||||
);
|
||||
}
|
@ -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 };
|
||||
}
|
||||
|
@ -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 };
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
export function Dashboard() {
|
||||
return <></>
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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}>
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user