about summary refs log tree commit diff
path: root/src/view/com/modals
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/modals')
-rw-r--r--src/view/com/modals/Confirm.tsx7
-rw-r--r--src/view/com/modals/DeleteAccount.tsx210
-rw-r--r--src/view/com/modals/EditProfile.tsx51
-rw-r--r--src/view/com/modals/Modal.tsx33
-rw-r--r--src/view/com/modals/Modal.web.tsx18
-rw-r--r--src/view/com/modals/ReportAccount.tsx30
-rw-r--r--src/view/com/modals/ReportPost.tsx37
-rw-r--r--src/view/com/modals/ServerInput.tsx13
-rw-r--r--src/view/com/modals/crop-image/CropImage.web.tsx8
9 files changed, 349 insertions, 58 deletions
diff --git a/src/view/com/modals/Confirm.tsx b/src/view/com/modals/Confirm.tsx
index 3e2ad6eea..60c104f99 100644
--- a/src/view/com/modals/Confirm.tsx
+++ b/src/view/com/modals/Confirm.tsx
@@ -7,9 +7,10 @@ import {
 } from 'react-native'
 import LinearGradient from 'react-native-linear-gradient'
 import {Text} from '../util/text/Text'
-import {useStores} from '../../../state'
-import {s, colors, gradients} from '../../lib/styles'
+import {useStores} from 'state/index'
+import {s, colors, gradients} from 'lib/styles'
 import {ErrorMessage} from '../util/error/ErrorMessage'
+import {cleanError} from 'lib/strings/errors'
 
 export const snapPoints = ['50%']
 
@@ -33,7 +34,7 @@ export function Component({
       store.shell.closeModal()
       return
     } catch (e: any) {
-      setError(e.toString())
+      setError(cleanError(e))
       setIsProcessing(false)
     }
   }
diff --git a/src/view/com/modals/DeleteAccount.tsx b/src/view/com/modals/DeleteAccount.tsx
new file mode 100644
index 000000000..de29e728d
--- /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/index'
+import {s, colors, gradients} from 'lib/styles'
+import {usePalette} from 'lib/hooks/usePalette'
+import {ErrorMessage} from '../util/error/ErrorMessage'
+import {cleanError} from 'lib/strings/errors'
+
+export const snapPoints = ['60%']
+
+export function Component({}: {}) {
+  const pal = usePalette('default')
+  const store = useStores()
+  const [isEmailSent, setIsEmailSent] = React.useState<boolean>(false)
+  const [confirmCode, setConfirmCode] = React.useState<string>('')
+  const [password, setPassword] = React.useState<string>('')
+  const [isProcessing, setIsProcessing] = React.useState<boolean>(false)
+  const [error, setError] = React.useState<string>('')
+  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 (
+    <View
+      style={[styles.container, {backgroundColor: pal.colors.backgroundLight}]}>
+      <View style={[styles.innerContainer, pal.view]}>
+        <Text type="title-xl" style={[styles.title, pal.text]}>
+          Delete account
+        </Text>
+        {!isEmailSent ? (
+          <>
+            <Text type="lg" style={[styles.description, pal.text]}>
+              For security reasons, we'll need to send a confirmation code to
+              your email.
+            </Text>
+            {error ? (
+              <View style={s.mt10}>
+                <ErrorMessage message={error} />
+              </View>
+            ) : undefined}
+            {isProcessing ? (
+              <View style={[styles.btn, s.mt10]}>
+                <ActivityIndicator />
+              </View>
+            ) : (
+              <>
+                <TouchableOpacity
+                  style={styles.mt20}
+                  onPress={onPressSendEmail}>
+                  <LinearGradient
+                    colors={[
+                      gradients.blueLight.start,
+                      gradients.blueLight.end,
+                    ]}
+                    start={{x: 0, y: 0}}
+                    end={{x: 1, y: 1}}
+                    style={[styles.btn]}>
+                    <Text type="button-lg" style={[s.white, s.bold]}>
+                      Send email
+                    </Text>
+                  </LinearGradient>
+                </TouchableOpacity>
+                <TouchableOpacity
+                  style={[styles.btn, s.mt10]}
+                  onPress={onCancel}>
+                  <Text type="button-lg" style={pal.textLight}>
+                    Cancel
+                  </Text>
+                </TouchableOpacity>
+              </>
+            )}
+          </>
+        ) : (
+          <>
+            <Text type="lg" style={styles.description}>
+              Check your inbox for an email with the confirmation code to enter
+              below:
+            </Text>
+            <BottomSheetTextInput
+              style={[styles.textInput, pal.borderDark, pal.text, styles.mb20]}
+              placeholder="Confirmation code"
+              placeholderTextColor={pal.textLight.color}
+              value={confirmCode}
+              onChangeText={setConfirmCode}
+            />
+            <Text type="lg" style={styles.description}>
+              Please enter your password as well:
+            </Text>
+            <BottomSheetTextInput
+              style={[styles.textInput, pal.borderDark, pal.text]}
+              placeholder="Password"
+              placeholderTextColor={pal.textLight.color}
+              secureTextEntry
+              value={password}
+              onChangeText={setPassword}
+            />
+            {error ? (
+              <View style={styles.mt20}>
+                <ErrorMessage message={error} />
+              </View>
+            ) : undefined}
+            {isProcessing ? (
+              <View style={[styles.btn, s.mt10]}>
+                <ActivityIndicator />
+              </View>
+            ) : (
+              <>
+                <TouchableOpacity
+                  style={[styles.btn, styles.evilBtn, styles.mt20]}
+                  onPress={onPressConfirmDelete}>
+                  <Text type="button-lg" style={[s.white, s.bold]}>
+                    Delete my account
+                  </Text>
+                </TouchableOpacity>
+                <TouchableOpacity
+                  style={[styles.btn, s.mt10]}
+                  onPress={onCancel}>
+                  <Text type="button-lg" style={pal.textLight}>
+                    Cancel
+                  </Text>
+                </TouchableOpacity>
+              </>
+            )}
+          </>
+        )}
+      </View>
+    </View>
+  )
+}
+
+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/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx
index 12b72a399..add75e89e 100644
--- a/src/view/com/modals/EditProfile.tsx
+++ b/src/view/com/modals/EditProfile.tsx
@@ -11,18 +11,17 @@ import {ScrollView, TextInput} from './util'
 import {PickedMedia} from '../util/images/image-crop-picker/ImageCropPicker'
 import {Text} from '../util/text/Text'
 import {ErrorMessage} from '../util/error/ErrorMessage'
-import {useStores} from '../../../state'
-import {ProfileViewModel} from '../../../state/models/profile-view'
-import {s, colors, gradients} from '../../lib/styles'
-import {
-  enforceLen,
-  MAX_DISPLAY_NAME,
-  MAX_DESCRIPTION,
-} from '../../../lib/strings'
-import {isNetworkError} from '../../../lib/errors'
-import {compressIfNeeded} from '../../../lib/images'
+import {useStores} from 'state/index'
+import {ProfileViewModel} from 'state/models/profile-view'
+import {s, colors, gradients} from 'lib/styles'
+import {enforceLen} from 'lib/strings/helpers'
+import {MAX_DISPLAY_NAME, MAX_DESCRIPTION} from 'lib/constants'
+import {compressIfNeeded} from 'lib/images'
 import {UserBanner} from '../util/UserBanner'
 import {UserAvatar} from '../util/UserAvatar'
+import {usePalette} from 'lib/hooks/usePalette'
+import {useAnalytics} from 'lib/analytics'
+import {cleanError, isNetworkError} from 'lib/strings/errors'
 
 export const snapPoints = ['80%']
 
@@ -35,6 +34,9 @@ export function Component({
 }) {
   const store = useStores()
   const [error, setError] = useState<string>('')
+  const pal = usePalette('default')
+  const {track} = useAnalytics()
+
   const [isProcessing, setProcessing] = useState<boolean>(false)
   const [displayName, setDisplayName] = useState<string>(
     profileView.displayName || '',
@@ -54,24 +56,27 @@ export function Component({
     store.shell.closeModal()
   }
   const onSelectNewAvatar = async (img: PickedMedia) => {
+    track('EditProfile:AvatarSelected')
     try {
-      const finalImg = await compressIfNeeded(img, 300000)
-      setNewUserAvatar(finalImg)
+      const finalImg = await compressIfNeeded(img, 1000000)
+      setNewUserAvatar({mediaType: 'photo', ...finalImg})
       setUserAvatar(finalImg.path)
     } catch (e: any) {
-      setError(e.message || e.toString())
+      setError(cleanError(e))
     }
   }
   const onSelectNewBanner = async (img: PickedMedia) => {
+    track('EditProfile:BannerSelected')
     try {
-      const finalImg = await compressIfNeeded(img, 500000)
-      setNewUserBanner(finalImg)
+      const finalImg = await compressIfNeeded(img, 1000000)
+      setNewUserBanner({mediaType: 'photo', ...finalImg})
       setUserBanner(finalImg.path)
     } catch (e: any) {
-      setError(e.message || e.toString())
+      setError(cleanError(e))
     }
   }
   const onPressSave = async () => {
+    track('EditProfile:Save')
     setProcessing(true)
     if (error) {
       setError('')
@@ -94,7 +99,7 @@ export function Component({
           'Failed to save your profile. Check your internet connection and try again.',
         )
       } else {
-        setError(e.message)
+        setError(cleanError(e))
       }
     }
     setProcessing(false)
@@ -103,13 +108,13 @@ export function Component({
   return (
     <View style={s.flex1}>
       <ScrollView style={styles.inner}>
-        <Text style={styles.title}>Edit my profile</Text>
+        <Text style={[styles.title, pal.text]}>Edit my profile</Text>
         <View style={styles.photos}>
           <UserBanner
             banner={userBanner}
             onSelectNewBanner={onSelectNewBanner}
           />
-          <View style={styles.avi}>
+          <View style={[styles.avi, {borderColor: pal.colors.background}]}>
             <UserAvatar
               size={80}
               avatar={userAvatar}
@@ -127,7 +132,7 @@ export function Component({
         <View>
           <Text style={styles.label}>Display Name</Text>
           <TextInput
-            style={styles.textInput}
+            style={[styles.textInput, pal.text]}
             placeholder="e.g. Alice Roberts"
             placeholderTextColor={colors.gray4}
             value={displayName}
@@ -135,9 +140,9 @@ export function Component({
           />
         </View>
         <View style={s.pb10}>
-          <Text style={styles.label}>Description</Text>
+          <Text style={[styles.label, pal.text]}>Description</Text>
           <TextInput
-            style={[styles.textArea]}
+            style={[styles.textArea, pal.text]}
             placeholder="e.g. Artist, dog-lover, and memelord."
             placeholderTextColor={colors.gray4}
             multiline
@@ -162,7 +167,7 @@ export function Component({
         )}
         <TouchableOpacity style={s.mt5} onPress={onPressCancel}>
           <View style={[styles.btn]}>
-            <Text style={[s.black, s.bold]}>Cancel</Text>
+            <Text style={[s.black, s.bold, pal.text]}>Cancel</Text>
           </View>
         </TouchableOpacity>
       </ScrollView>
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index d0b40d56d..2529d0d5b 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -2,23 +2,26 @@ import React, {useRef, useEffect} from 'react'
 import {View} from 'react-native'
 import {observer} from 'mobx-react-lite'
 import BottomSheet from '@gorhom/bottom-sheet'
-import {useStores} from '../../../state'
+import {useStores} from 'state/index'
 import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
 
-import * as models from '../../../state/models/shell-ui'
+import * as models from 'state/models/shell-ui'
 
 import * as ConfirmModal from './Confirm'
 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'
 
 const CLOSED_SNAPPOINTS = ['10%']
 
 export const Modal = observer(function Modal() {
   const store = useStores()
   const bottomSheetRef = useRef<BottomSheet>(null)
-
+  const pal = usePalette('default')
   const onBottomSheetChange = (snapPoint: number) => {
     if (snapPoint === -1) {
       store.shell.closeModal()
@@ -62,10 +65,21 @@ export const Modal = observer(function Modal() {
     )
   } else if (store.shell.activeModal?.name === 'report-post') {
     snapPoints = ReportPostModal.snapPoints
-    element = <ReportPostModal.Component />
+    element = (
+      <ReportPostModal.Component
+        {...(store.shell.activeModal as models.ReportPostModal)}
+      />
+    )
   } else if (store.shell.activeModal?.name === 'report-account') {
     snapPoints = ReportAccountModal.snapPoints
-    element = <ReportAccountModal.Component />
+    element = (
+      <ReportAccountModal.Component
+        {...(store.shell.activeModal as models.ReportAccountModal)}
+      />
+    )
+  } else if (store.shell.activeModal?.name === 'delete-account') {
+    snapPoints = DeleteAccountModal.snapPoints
+    element = <DeleteAccountModal.Component />
   } else {
     element = <View />
   }
@@ -80,8 +94,17 @@ export const Modal = observer(function Modal() {
       backdropComponent={
         store.shell.isModalActive ? createCustomBackdrop(onClose) : undefined
       }
+      handleIndicatorStyle={{backgroundColor: pal.text.color}}
+      handleStyle={[styles.handle, pal.view]}
       onChange={onBottomSheetChange}>
       {element}
     </BottomSheet>
   )
 })
+
+const styles = StyleSheet.create({
+  handle: {
+    borderTopLeftRadius: 10,
+    borderTopRightRadius: 10,
+  },
+})
diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx
index 44ea95f07..3c6551093 100644
--- a/src/view/com/modals/Modal.web.tsx
+++ b/src/view/com/modals/Modal.web.tsx
@@ -1,10 +1,10 @@
 import React from 'react'
 import {TouchableWithoutFeedback, StyleSheet, View} from 'react-native'
 import {observer} from 'mobx-react-lite'
-import {useStores} from '../../../state'
-import {usePalette} from '../../lib/hooks/usePalette'
+import {useStores} from 'state/index'
+import {usePalette} from 'lib/hooks/usePalette'
 
-import * as models from '../../../state/models/shell-ui'
+import * as models from 'state/models/shell-ui'
 
 import * as ConfirmModal from './Confirm'
 import * as EditProfileModal from './EditProfile'
@@ -48,9 +48,17 @@ export const Modal = observer(function Modal() {
       />
     )
   } else if (store.shell.activeModal?.name === 'report-post') {
-    element = <ReportPostModal.Component />
+    element = (
+      <ReportPostModal.Component
+        {...(store.shell.activeModal as models.ReportPostModal)}
+      />
+    )
   } else if (store.shell.activeModal?.name === 'report-account') {
-    element = <ReportAccountModal.Component />
+    element = (
+      <ReportAccountModal.Component
+        {...(store.shell.activeModal as models.ReportAccountModal)}
+      />
+    )
   } else if (store.shell.activeModal?.name === 'crop-image') {
     element = (
       <CropImageModal.Component
diff --git a/src/view/com/modals/ReportAccount.tsx b/src/view/com/modals/ReportAccount.tsx
index 1385d5711..377a32838 100644
--- a/src/view/com/modals/ReportAccount.tsx
+++ b/src/view/com/modals/ReportAccount.tsx
@@ -5,12 +5,15 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
+import {ComAtprotoReportReasonType} from '@atproto/api'
 import LinearGradient from 'react-native-linear-gradient'
-import {useStores} from '../../../state'
-import {s, colors, gradients} from '../../lib/styles'
+import {useStores} from 'state/index'
+import {s, colors, gradients} from 'lib/styles'
 import {RadioGroup, RadioGroupItem} from '../util/forms/RadioGroup'
 import {Text} from '../util/text/Text'
+import * as Toast from '../util/Toast'
 import {ErrorMessage} from '../util/error/ErrorMessage'
+import {cleanError} from 'lib/strings/errors'
 
 const ITEMS: RadioGroupItem[] = [
   {key: 'spam', label: 'Spam or excessive repeat posts'},
@@ -20,7 +23,7 @@ const ITEMS: RadioGroupItem[] = [
 
 export const snapPoints = ['50%']
 
-export function Component() {
+export function Component({did}: {did: string}) {
   const store = useStores()
   const [isProcessing, setIsProcessing] = useState<boolean>(false)
   const [error, setError] = useState<string>('')
@@ -28,13 +31,30 @@ export function Component() {
   const onSelectIssue = (v: string) => setIssue(v)
   const onPress = async () => {
     setError('')
+    if (!issue) {
+      return
+    }
     setIsProcessing(true)
     try {
-      // TODO
+      // NOTE: we should update the lexicon of reasontype to include more options -prf
+      let reasonType = ComAtprotoReportReasonType.OTHER
+      if (issue === 'spam') {
+        reasonType = ComAtprotoReportReasonType.SPAM
+      }
+      const reason = ITEMS.find(item => item.key === issue)?.label || ''
+      await store.api.com.atproto.report.create({
+        reasonType,
+        reason,
+        subject: {
+          $type: 'com.atproto.repo.repoRef',
+          did,
+        },
+      })
+      Toast.show("Thank you for your report! We'll look into it promptly.")
       store.shell.closeModal()
       return
     } catch (e: any) {
-      setError(e.toString())
+      setError(cleanError(e))
       setIsProcessing(false)
     }
   }
diff --git a/src/view/com/modals/ReportPost.tsx b/src/view/com/modals/ReportPost.tsx
index 8a3a1f758..3d47e7ef0 100644
--- a/src/view/com/modals/ReportPost.tsx
+++ b/src/view/com/modals/ReportPost.tsx
@@ -5,12 +5,15 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
+import {ComAtprotoReportReasonType} from '@atproto/api'
 import LinearGradient from 'react-native-linear-gradient'
-import {useStores} from '../../../state'
-import {s, colors, gradients} from '../../lib/styles'
+import {useStores} from 'state/index'
+import {s, colors, gradients} from 'lib/styles'
 import {RadioGroup, RadioGroupItem} from '../util/forms/RadioGroup'
 import {Text} from '../util/text/Text'
+import * as Toast from '../util/Toast'
 import {ErrorMessage} from '../util/error/ErrorMessage'
+import {cleanError} from 'lib/strings/errors'
 
 const ITEMS: RadioGroupItem[] = [
   {key: 'spam', label: 'Spam or excessive repeat posts'},
@@ -21,7 +24,13 @@ const ITEMS: RadioGroupItem[] = [
 
 export const snapPoints = ['50%']
 
-export function Component() {
+export function Component({
+  postUri,
+  postCid,
+}: {
+  postUri: string
+  postCid: string
+}) {
   const store = useStores()
   const [isProcessing, setIsProcessing] = useState<boolean>(false)
   const [error, setError] = useState<string>('')
@@ -29,13 +38,31 @@ export function Component() {
   const onSelectIssue = (v: string) => setIssue(v)
   const onPress = async () => {
     setError('')
+    if (!issue) {
+      return
+    }
     setIsProcessing(true)
     try {
-      // TODO
+      // NOTE: we should update the lexicon of reasontype to include more options -prf
+      let reasonType = ComAtprotoReportReasonType.OTHER
+      if (issue === 'spam') {
+        reasonType = ComAtprotoReportReasonType.SPAM
+      }
+      const reason = ITEMS.find(item => item.key === issue)?.label || ''
+      await store.api.com.atproto.report.create({
+        reasonType,
+        reason,
+        subject: {
+          $type: 'com.atproto.repo.recordRef',
+          uri: postUri,
+          cid: postCid,
+        },
+      })
+      Toast.show("Thank you for your report! We'll look into it promptly.")
       store.shell.closeModal()
       return
     } catch (e: any) {
-      setError(e.toString())
+      setError(cleanError(e))
       setIsProcessing(false)
     }
   }
diff --git a/src/view/com/modals/ServerInput.tsx b/src/view/com/modals/ServerInput.tsx
index dde836719..5a9a4cfed 100644
--- a/src/view/com/modals/ServerInput.tsx
+++ b/src/view/com/modals/ServerInput.tsx
@@ -6,14 +6,10 @@ import {
 } from '@fortawesome/react-native-fontawesome'
 import {ScrollView, TextInput} from './util'
 import {Text} from '../util/text/Text'
-import {useStores} from '../../../state'
-import {s, colors} from '../../lib/styles'
-import {
-  LOCAL_DEV_SERVICE,
-  STAGING_SERVICE,
-  PROD_SERVICE,
-} from '../../../state/index'
-import {LOGIN_INCLUDE_DEV_SERVERS} from '../../../build-flags'
+import {useStores} from 'state/index'
+import {s, colors} from 'lib/styles'
+import {LOCAL_DEV_SERVICE, STAGING_SERVICE, PROD_SERVICE} from 'state/index'
+import {LOGIN_INCLUDE_DEV_SERVERS} from 'lib/build-flags'
 
 export const snapPoints = ['80%']
 
@@ -37,6 +33,7 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
           {LOGIN_INCLUDE_DEV_SERVERS ? (
             <>
               <TouchableOpacity
+                testID="localDevServerButton"
                 style={styles.btn}
                 onPress={() => doSelect(LOCAL_DEV_SERVICE)}>
                 <Text style={styles.btnText}>Local dev server</Text>
diff --git a/src/view/com/modals/crop-image/CropImage.web.tsx b/src/view/com/modals/crop-image/CropImage.web.tsx
index 1f234c4a6..e43f37397 100644
--- a/src/view/com/modals/crop-image/CropImage.web.tsx
+++ b/src/view/com/modals/crop-image/CropImage.web.tsx
@@ -5,10 +5,10 @@ import {Slider} from '@miblanchard/react-native-slider'
 import LinearGradient from 'react-native-linear-gradient'
 import {Text} from '../../util/text/Text'
 import {PickedMedia} from '../../util/images/image-crop-picker/types'
-import {s, gradients} from '../../../lib/styles'
-import {useStores} from '../../../../state'
-import {usePalette} from '../../../lib/hooks/usePalette'
-import {SquareIcon, RectWideIcon, RectTallIcon} from '../../../lib/icons'
+import {s, gradients} from 'lib/styles'
+import {useStores} from 'state/index'
+import {usePalette} from 'lib/hooks/usePalette'
+import {SquareIcon, RectWideIcon, RectTallIcon} from 'lib/icons'
 
 enum AspectRatio {
   Square = 'square',