adding delete account modal

This commit is contained in:
balzack 2024-09-26 18:35:54 -07:00
parent fe04521e07
commit 03cd108cb3
9 changed files with 168 additions and 6 deletions

View File

@ -31,6 +31,7 @@ const Strings = [
monthEnd: 'dd/mm',
error: 'Error',
tryAgain: 'Please try again.',
allDevices: 'Logout of all devices',
// seal wizard
sealUnset: 'Generate a key to enable end-to-end encrypted topics.',
@ -246,6 +247,7 @@ const Strings = [
monthEnd: 'jj/mm',
error: 'Erreur',
tryAgain: 'Veuillez réessayer.',
allDevices: 'Déconnexion de tous les appareils',
messages: 'Messages',
sealUnset:
@ -461,6 +463,7 @@ const Strings = [
monthEnd: 'dd/mm',
error: 'Error',
tryAgain: 'Inténtalo de nuevo.',
allDevices: 'Cerrar sesión en todos los dispositivos',
sealUnset:
'Genere una clave para habilitar temas cifrados de un extremo a otro.',
@ -673,6 +676,7 @@ const Strings = [
monthEnd: 'dd/mm',
error: 'Fehler',
tryAgain: 'Bitte versuche es erneut.',
allDevices: 'Abmelden aller Geräte',
sealUnset:
'Generieren Sie einen Schlüssel, um Ende-zu-Ende-verschlüsselte Themen zu ermöglichen.',
@ -1038,6 +1042,7 @@ const Strings = [
start: 'Crie Uma Conversa',
started: 'Iniciar',
allDevices: 'Sair de todos os dispositivos',
deleteMessage: 'Apagar Mensagem',
blockMessage: 'Bloquear Mensagem',
reportMessage: 'Denunciar Mensagem',
@ -1183,6 +1188,7 @@ const Strings = [
guest: 'Гость',
leave: 'Покинуть',
members: 'Участники',
allDevices: 'Выход из всех устройств',
editSubject: 'Редактировать тему',
topicMembers: 'Участники темы',
leaveTopic: 'Покинуть тему',

View File

@ -77,12 +77,18 @@ export function useAppContext() {
);
updateState({session: login});
},
accountLogout: async () => {
accountLogout: async (all: boolean) => {
if (state.session) {
await sdk.current.logout(state.session, false);
await sdk.current.logout(state.session, all);
updateState({session: null});
}
},
accountRemove: async () => {
if (state.session) {
await sdk.current.remove(state.session);
updateState({ session: null });
}
},
accountCreate: async (
handle: string,
password: string,

View File

@ -28,6 +28,9 @@ export const styles = StyleSheet.create({
height: '100%',
gap: 8,
},
remove: {
backgroundColor: Colors.danger,
},
surface: {
padding: 16,
},
@ -211,6 +214,14 @@ export const styles = StyleSheet.create({
fontSize: 16,
flexGrow: 1,
},
allControl: {
flexShrink: 1,
flexGrow: 1,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
paddingTop: 16,
},
control: {
flexShrink: 1,
flexGrow: 1,

View File

@ -18,6 +18,10 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
const [auth, setAuth] = useState(false);
const [clear, setClear] = useState(false);
const [change, setChange] = useState(false);
const [logout, setLogout] = useState(false);
const [remove, setRemove] = useState(false);
const [applyingLogout, setApplyingLogout] = useState(false);
const [applyingRemove, setApplyingRemove] = useState(false);
const [sealDelete, setSealDelete] = useState(false);
const [sealReset, setSealReset] = useState(false);
const [sealConfig, setSealConfig] = useState(false);
@ -70,6 +74,38 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
}
}
const applyRemove = async () => {
if (!applyingRemove) {
setApplyingRemove(true);
try {
await actions.remove();
setRemove(false);
}
catch (err) {
console.log(err);
setRemove(false);
setAlert(true);
}
setApplyingRemove(false);
}
}
const applyLogout = async () => {
if (!applyingLogout) {
setApplyingLogout(true);
try {
await actions.logout();
setLogout(false);
}
catch (err) {
console.log(err);
setLogout(false);
setAlert(true);
}
setApplyingLogout(false);
}
}
const setMfa = async (flag: boolean) => {
if (!savingAuth) {
setSavingAuth(true);
@ -404,7 +440,7 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
<Icon size={24} source="logout" />
</View>
<View style={styles.control}>
<TouchableOpacity activeOpacity={1} onPress={() => manageSeal}>
<TouchableOpacity activeOpacity={1} onPress={() => setLogout(true)}>
<Text style={styles.controlLabel}>{state.strings.logout}</Text>
</TouchableOpacity>
</View>
@ -415,7 +451,7 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
<Icon size={24} source="account-remove" />
</View>
<View style={styles.control}>
<TouchableOpacity activeOpacity={1} onPress={() => manageSeal}>
<TouchableOpacity activeOpacity={1} onPress={() => setRemove(true)}>
<Text style={styles.dangerLabel}>{state.strings.deleteAccount}</Text>
</TouchableOpacity>
</View>
@ -941,6 +977,75 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
</KeyboardAwareScrollView>
</View>
</Modal>
<Modal
animationType="fade"
transparent={true}
supportedOrientations={['portrait', 'landscape']}
visible={logout}
onRequestClose={() => setLogout(false)}>
<View style={styles.modal}>
<BlurView
style={styles.blur}
blurType="dark"
blurAmount={2}
reducedTransparencyFallbackColor="dark"
/>
<KeyboardAwareScrollView style={styles.container} contentContainerStyle={styles.content}>
<Surface elevation={5} mode="flat" style={styles.surface}>
<Text style={styles.modalLabel}>{ state.strings.loggingOut }</Text>
<IconButton style={styles.modalClose} icon="close" size={24} onPress={() => setLogout(false)} />
<View style={styles.allControl}>
<Text style={styles.controlLabel}>{state.strings.allDevices}</Text>
<Switch style={styles.controlSwitch} value={state.all} onValueChange={actions.setAll} />
</View>
<View style={styles.modalControls}>
<Button mode="outlined" onPress={() => setLogout(false)}>{ state.strings.cancel }</Button>
<Button mode="contained" loading={applyingLogout} onPress={applyLogout}>{ state.strings.logout }</Button>
</View>
</Surface>
</KeyboardAwareScrollView>
</View>
</Modal>
<Modal
animationType="fade"
transparent={true}
supportedOrientations={['portrait', 'landscape']}
visible={remove}
onRequestClose={() => setRemove(false)}>
<View style={styles.modal}>
<BlurView
style={styles.blur}
blurType="dark"
blurAmount={2}
reducedTransparencyFallbackColor="dark"
/>
<KeyboardAwareScrollView style={styles.container} contentContainerStyle={styles.content}>
<Surface elevation={5} mode="flat" style={styles.surface}>
<Text style={styles.modalLabel}>{ state.strings.deleteAccount }</Text>
<IconButton style={styles.modalClose} icon="close" size={24} onPress={() => setRemove(false)} />
<TextInput
style={styles.input}
mode="flat"
autoCapitalize="none"
autoComplete="off"
autoCorrect={false}
value={state.remove}
label={state.strings.typeDelete}
left={<TextInput.Icon style={styles.icon} icon="delete-outline" />}
onChangeText={value => actions.setRemove(value)}
/>
<View style={styles.modalControls}>
<Button mode="outlined" onPress={() => setRemove(false)}>{ state.strings.cancel }</Button>
<Button mode="contained" loading={applyingRemove} disabled={state.remove !== state.strings.deleteKey} style={styles.remove} onPress={applyRemove}>{ state.strings.delete }</Button>
</View>
</Surface>
</KeyboardAwareScrollView>
</View>
</Modal>
</>
);

View File

@ -19,6 +19,7 @@ export function useSettings() {
all: false,
password: '',
confirm: '',
remove: '',
username: '',
taken: false,
checked: true,
@ -192,6 +193,9 @@ export function useSettings() {
logout: async () => {
await app.actions.accountLogout(state.all)
},
remove: async () => {
await app.actions.accountRemove()
},
setHandle: (handle: string) => {
updateState({ handle, taken: false, checked: false })
clearTimeout(debounce.current)
@ -216,6 +220,9 @@ export function useSettings() {
setConfirm: (confirm: string) => {
updateState({ confirm })
},
setRemove: (remove: string) => {
updateState({ remove });
},
setName: (name: string) => {
updateState({ name })
},

View File

@ -56,9 +56,9 @@ export function useAppContext() {
)
updateState({ session: login })
},
accountLogout: async () => {
accountLogout: async (all: boolean) => {
if (state.session) {
await sdk.current.logout(state.session, false)
await sdk.current.logout(state.session, all)
updateState({ session: null })
}
},

View File

@ -53,6 +53,7 @@ export interface Settings {
unlockSeal(password: string): Promise<void>;
updaterSeal(password: string): Promise<void>;
forgetSeal(): Promise<void>;
deleteAccount(): Promise<void>;
addConfigListener(ev: (config: Config) => void): void;
removeConfigListener(ev: (config: Config) => void): void;

View File

@ -5,6 +5,7 @@ import { type Logging, ConsoleLogging } from './logging';
import { type Store, OfflineStore, OnlineStore, NoStore } from './store';
import { setLogin } from './net/setLogin';
import { clearLogin } from './net/clearLogin';
import { removeAccount } from './net/removeAccount';
import { setAccess } from './net/setAccess';
import { addAccount } from './net/addAccount';
import { setAdmin } from './net/setAdmin';
@ -79,6 +80,24 @@ export class DatabagSDK {
return new SessionModule(this.store, this.crypto, this.log, guid, appToken, node, secure, created);
}
public async remove(session: Session): Promise<void> {
const sessionModule = session as SessionModule;
const params = await sessionModule.close();
try {
await this.store.clearLogin();
}
catch(err) {
this.log.error(err);
}
try {
const { node, secure, token } = params;
await removeAccount(node, secure, token);
}
catch(err) {
this.log.error(err);
}
}
public async logout(session: Session, all: boolean): Promise<void> {
const sessionModule = session as SessionModule;
const params = await sessionModule.close();

View File

@ -0,0 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeAccount(node: string, secure: boolean, token: string): Promise<void> {
const endpoint = `http${secure ? 's' : ''}://${node}/profile?agent=${token}`;
const { status } = await fetchWithTimeout(endpoint, { method: 'DELETE' })
checkResponse(status);
}