diff --git a/package.json b/package.json index f6710d8679..71a4944621 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "lint": "eslint . --ext .js,.jsx,.ts,.tsx" }, "dependencies": { - "@atproto/api": "^0.0.7", + "@atproto/api": "^0.0.8", "@atproto/lexicon": "^0.0.4", "@atproto/xrpc": "^0.0.3", "@bam.tech/react-native-image-resizer": "^3.0.4", diff --git a/src/state/models/shell-ui.ts b/src/state/models/shell-ui.ts index b84d6ece98..9fd1a851e5 100644 --- a/src/state/models/shell-ui.ts +++ b/src/state/models/shell-ui.ts @@ -52,6 +52,14 @@ export class ReportAccountModal { } } +export class DeleteAccountModal { + name = 'delete-account' + + constructor() { + makeAutoObservable(this) + } +} + interface LightboxModel {} export class ProfileImageLightbox implements LightboxModel { @@ -98,6 +106,7 @@ export class ShellUiModel { | ServerInputModal | ReportPostModal | ReportAccountModal + | DeleteAccountModal | undefined isLightboxActive = false activeLightbox: ProfileImageLightbox | ImagesLightbox | undefined @@ -140,7 +149,8 @@ export class ShellUiModel { | EditProfileModal | ServerInputModal | ReportPostModal - | ReportAccountModal, + | ReportAccountModal + | DeleteAccountModal, ) { this.isModalActive = true this.activeModal = modal diff --git a/src/view/com/modals/DeleteAccount.tsx b/src/view/com/modals/DeleteAccount.tsx new file mode 100644 index 0000000000..3e614c04e7 --- /dev/null +++ b/src/view/com/modals/DeleteAccount.tsx @@ -0,0 +1,210 @@ +import React from 'react' +import { + ActivityIndicator, + StyleSheet, + TouchableOpacity, + View, +} from 'react-native' +import {BottomSheetTextInput} from '@gorhom/bottom-sheet' +import LinearGradient from 'react-native-linear-gradient' +import * as Toast from '../util/Toast' +import {Text} from '../util/text/Text' +import {useStores} from '../../../state' +import {s, colors, gradients} from '../../lib/styles' +import {usePalette} from '../../lib/hooks/usePalette' +import {ErrorMessage} from '../util/error/ErrorMessage' +import {cleanError} from '../../../lib/strings' + +export const snapPoints = ['60%'] + +export function Component({}: {}) { + const pal = usePalette('default') + const store = useStores() + const [isEmailSent, setIsEmailSent] = React.useState(false) + const [confirmCode, setConfirmCode] = React.useState('') + const [password, setPassword] = React.useState('') + const [isProcessing, setIsProcessing] = React.useState(false) + const [error, setError] = React.useState('') + const onPressSendEmail = async () => { + setError('') + setIsProcessing(true) + try { + await store.api.com.atproto.account.requestDelete() + setIsEmailSent(true) + } catch (e: any) { + setError(cleanError(e)) + } + setIsProcessing(false) + } + const onPressConfirmDelete = async () => { + setError('') + setIsProcessing(true) + try { + await store.api.com.atproto.account.delete({ + did: store.me.did, + password, + token: confirmCode, + }) + Toast.show('Your account has been deleted') + store.nav.tab.fixedTabReset() + store.session.clear() + store.shell.closeModal() + } catch (e: any) { + setError(cleanError(e)) + } + setIsProcessing(false) + } + const onCancel = () => { + store.shell.closeModal() + } + return ( + + + + Delete account + + {!isEmailSent ? ( + <> + + For security reasons, we'll need to send a confirmation code to + your email. + + {error ? ( + + + + ) : undefined} + {isProcessing ? ( + + + + ) : ( + <> + + + + Send email + + + + + + Cancel + + + + )} + + ) : ( + <> + + Check your inbox for an email with the confirmation code to enter + below: + + + + Please enter your password as well: + + + {error ? ( + + + + ) : undefined} + {isProcessing ? ( + + + + ) : ( + <> + + + Delete my account + + + + + Cancel + + + + )} + + )} + + + ) +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + innerContainer: { + paddingBottom: 20, + }, + title: { + textAlign: 'center', + marginTop: 12, + marginBottom: 12, + }, + description: { + textAlign: 'center', + paddingHorizontal: 22, + marginBottom: 10, + }, + mt20: { + marginTop: 20, + }, + mb20: { + marginBottom: 20, + }, + textInput: { + borderWidth: 1, + borderRadius: 6, + paddingHorizontal: 16, + paddingVertical: 12, + fontSize: 20, + marginHorizontal: 20, + }, + btn: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + borderRadius: 32, + padding: 14, + marginHorizontal: 20, + }, + evilBtn: { + backgroundColor: colors.red4, + }, +}) diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx index 1f77d91801..ed9dfe3809 100644 --- a/src/view/com/modals/Modal.tsx +++ b/src/view/com/modals/Modal.tsx @@ -12,6 +12,7 @@ import * as EditProfileModal from './EditProfile' import * as ServerInputModal from './ServerInput' import * as ReportPostModal from './ReportPost' import * as ReportAccountModal from './ReportAccount' +import * as DeleteAccountModal from './DeleteAccount' import {usePalette} from '../../lib/hooks/usePalette' import {StyleSheet} from 'react-native' @@ -76,6 +77,9 @@ export const Modal = observer(function Modal() { {...(store.shell.activeModal as models.ReportAccountModal)} /> ) + } else if (store.shell.activeModal?.name === 'delete-account') { + snapPoints = DeleteAccountModal.snapPoints + element = } else { element = } diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index 2f98fce2dc..77631397c2 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -107,7 +107,7 @@ export const ProfileHeader = observer(function ProfileHeader({ - + {view.displayName || view.handle} @@ -200,7 +200,7 @@ export const ProfileHeader = observer(function ProfileHeader({ ) : undefined} - + {view.displayName || view.handle} diff --git a/src/view/lib/ThemeContext.tsx b/src/view/lib/ThemeContext.tsx index 16a7d9cb3d..bcfc076f4e 100644 --- a/src/view/lib/ThemeContext.tsx +++ b/src/view/lib/ThemeContext.tsx @@ -53,6 +53,7 @@ export type TypographyVariant = | 'xs-medium' | 'xs-bold' | 'xs-heavy' + | 'title-2xl' | 'title-xl' | 'title-lg' | 'title' @@ -60,6 +61,7 @@ export type TypographyVariant = | 'post-text-lg' | 'post-text' | 'button' + | 'button-lg' | 'mono' export type Typography = Record diff --git a/src/view/lib/themes.ts b/src/view/lib/themes.ts index 84e2b7883b..39b6ca97aa 100644 --- a/src/view/lib/themes.ts +++ b/src/view/lib/themes.ts @@ -208,11 +208,16 @@ export const defaultTheme: Theme = { fontWeight: '800', }, - 'title-xl': { + 'title-2xl': { fontSize: 34, letterSpacing: 0.25, fontWeight: '500', }, + 'title-xl': { + fontSize: 28, + letterSpacing: 0.25, + fontWeight: '500', + }, 'title-lg': { fontSize: 22, fontWeight: '500', @@ -237,6 +242,11 @@ export const defaultTheme: Theme = { letterSpacing: 0.4, fontWeight: '400', }, + 'button-lg': { + fontWeight: '500', + fontSize: 18, + letterSpacing: 0.5, + }, button: { fontWeight: '500', fontSize: 14, diff --git a/src/view/screens/Debug.tsx b/src/view/screens/Debug.tsx index 865f62dc6a..45ded0dce9 100644 --- a/src/view/screens/Debug.tsx +++ b/src/view/screens/Debug.tsx @@ -293,6 +293,9 @@ function TypographyView() { 'xs-heavy' lorem ipsum dolor + + 'title-2xl' lorem ipsum dolor + 'title-xl' lorem ipsum dolor @@ -305,6 +308,9 @@ function TypographyView() { Button + + Button-lg + ) } diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx index 8190b48a70..d874184ba5 100644 --- a/src/view/screens/Settings.tsx +++ b/src/view/screens/Settings.tsx @@ -18,6 +18,7 @@ import * as Toast from '../com/util/Toast' import {UserAvatar} from '../com/util/UserAvatar' import {usePalette} from '../lib/hooks/usePalette' import {AccountData} from '../../state/models/session' +import {DeleteAccountModal} from '../../state/models/shell-ui' export const Settings = observer(function Settings({ navIdx, @@ -54,6 +55,9 @@ export const Settings = observer(function Settings({ const onPressSignout = () => { store.session.logout() } + const onPressDeleteAccount = () => { + store.shell.openModal(new DeleteAccountModal()) + } return ( @@ -146,19 +150,27 @@ export const Settings = observer(function Settings({ + Danger zone + + + Delete my account + + Developer tools - System log + System log - Storybook + Storybook diff --git a/yarn.lock b/yarn.lock index 2561939881..80796348be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19,10 +19,10 @@ jsonpointer "^5.0.0" leven "^3.1.0" -"@atproto/api@^0.0.7": - version "0.0.7" - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.0.7.tgz#2cec239dd252a67a768a715e385fa835e834c280" - integrity sha512-2iQ5fd8YG4H5MzcWYtlvemOoXqzhRaxkNblecw1+iopTQjPrrDntJwKIg7+qLW0Mr93w+RSLmmekWUkiIJf1ew== +"@atproto/api@^0.0.8": + version "0.0.8" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.0.8.tgz#ff01bb193cd1dad422916572ff595a625fa3cc06" + integrity sha512-qEnrzy8vKnt3yEjRCmKUnTvW6GKPB9pB5PP1+qIfUnQ7Sqrb793LtaSXPk9ZnrvtL3fsxYnfUY+7KB2X4osSyA== dependencies: "@atproto/xrpc" "*" typed-emitter "^2.1.0"