diff --git a/shared/constants/settings.tsx b/shared/constants/settings.tsx
index b54c44d6f26e..b3be63c307c3 100644
--- a/shared/constants/settings.tsx
+++ b/shared/constants/settings.tsx
@@ -12,7 +12,6 @@ export const settingsFeedbackTab = 'settingsTabs.feedbackTab'
export const settingsFoldersTab = 'settingsTabs.foldersTab'
export const settingsFsTab = 'settingsTabs.fsTab'
export const settingsGitTab = 'settingsTabs.gitTab'
-export const settingsInvitationsTab = 'settingsTabs.invitationsTab'
export const settingsAccountTab = 'settingsTabs.accountTab'
export const settingsNotificationsTab = 'settingsTabs.notificationsTab'
export const settingsPasswordTab = 'settingsTabs.password'
@@ -26,7 +25,6 @@ export const settingsWhatsNewTab = 'settingsTabs.whatsNewTab'
export type SettingsTab =
| typeof settingsAccountTab
| typeof settingsUpdatePaymentTab
- | typeof settingsInvitationsTab
| typeof settingsNotificationsTab
| typeof settingsAdvancedTab
| typeof settingsFeedbackTab
diff --git a/shared/settings/invite-generated/index.d.ts b/shared/settings/invite-generated/index.d.ts
deleted file mode 100644
index b9eaba61f7e5..000000000000
--- a/shared/settings/invite-generated/index.d.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import type * as React from 'react'
-
-export type Props = {
- email?: string
- link: string
-}
-
-export declare const InviteGeneratedRender: (p: Props) => React.ReactNode
-declare const InviteGenerated: (p: Props) => React.ReactNode
-export default InviteGenerated
diff --git a/shared/settings/invite-generated/index.desktop.tsx b/shared/settings/invite-generated/index.desktop.tsx
deleted file mode 100644
index fb4f70956367..000000000000
--- a/shared/settings/invite-generated/index.desktop.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import * as Kb from '@/common-adapters'
-import * as C from '@/constants'
-import type {Props} from '.'
-
-const InviteGeneratedRender = (props: Props) => {
- const {link, email} = props
- const onClose = C.useRouterState(s => s.dispatch.navigateUp)
- return (
-
-
-
- {email ? (
-
- Yay! We emailed {email}, but you can also give them the below
- link:
-
- ) : (
-
- Yay! Please share the below link with your friend. It contains signup & install instructions.
-
- )}
-
-
-
- {link}
-
-
-
-
- )
-}
-
-const styles = Kb.Styles.styleSheetCreate(() => ({
- icon: Kb.Styles.platformStyles({
- isElectron: {
- ...Kb.Styles.desktopStyles.clickable,
- position: 'absolute',
- right: Kb.Styles.globalMargins.small,
- top: Kb.Styles.globalMargins.small,
- },
- }),
- linkContainer: {
- backgroundColor: Kb.Styles.globalColors.greenLighter,
- borderRadius: Kb.Styles.borderRadius,
- height: 32,
- marginTop: Kb.Styles.globalMargins.tiny,
- paddingLeft: Kb.Styles.globalMargins.xsmall,
- paddingRight: Kb.Styles.globalMargins.xsmall,
- },
-
- text: {
- paddingTop: Kb.Styles.globalMargins.medium,
- width: 440,
- },
-}))
-export default InviteGeneratedRender
diff --git a/shared/settings/invite-generated/index.native.tsx b/shared/settings/invite-generated/index.native.tsx
deleted file mode 100644
index db77d626ea6b..000000000000
--- a/shared/settings/invite-generated/index.native.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-function InviteGenerated() {
- return null
-}
-
-export default InviteGenerated
diff --git a/shared/settings/invites/index.d.ts b/shared/settings/invites/index.d.ts
deleted file mode 100644
index 234efc321d71..000000000000
--- a/shared/settings/invites/index.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import type * as React from 'react'
-declare const Invites: () => React.ReactNode
-export default Invites
diff --git a/shared/settings/invites/index.desktop.tsx b/shared/settings/invites/index.desktop.tsx
deleted file mode 100644
index 9389385972b9..000000000000
--- a/shared/settings/invites/index.desktop.tsx
+++ /dev/null
@@ -1,256 +0,0 @@
-import * as Kb from '@/common-adapters'
-import type {AcceptedInvite, PendingInvite} from '@/stores/settings-invites'
-import * as React from 'react'
-import SubHeading from '../subheading'
-import * as dateFns from 'date-fns'
-import * as C from '@/constants'
-import {useProfileState} from '@/stores/profile'
-import {useState as useSettingsInvitesState} from '@/stores/settings-invites'
-
-// Like intersperse but takes a function to define the separator
-function intersperseFn(
- separatorFn: (index: number, x: A, a: Array) => B,
- arr: Array
-): Array {
- if (arr.length === 0) {
- return arr
- }
-
- const toReturn = new Array(arr.length * 2 - 1)
- toReturn[0] = arr[0]!
- for (let i = 1; i < arr.length; i++) {
- toReturn[i * 2 - 1] = separatorFn(i, arr[i]!, arr)
- toReturn[i * 2] = arr[i]!
- }
- return toReturn
-}
-
-const Invites = () => {
- const invitesState = useSettingsInvitesState(
- C.useShallow(s => ({
- acceptedInvites: s.acceptedInvites,
- error: s.error,
- loadInvites: s.dispatch.loadInvites,
- pendingInvites: s.pendingInvites,
- reclaimInvite: s.dispatch.reclaimInvite,
- resetError: s.dispatch.resetError,
- sendInvite: s.dispatch.sendInvite,
- }))
- )
- const {acceptedInvites, error, loadInvites, pendingInvites} = invitesState
- const {reclaimInvite, resetError, sendInvite} = invitesState
- const waitingForResponse = C.Waiting.useAnyWaiting(C.waitingKeySettingsGeneric)
- const onClearError = resetError
- const onGenerateInvitation = sendInvite
- const onReclaimInvitation = reclaimInvite
- const onRefresh = loadInvites
- const navigateAppend = C.useRouterState(s => s.dispatch.navigateAppend)
- const onSelectPendingInvite = (invite: PendingInvite) => {
- navigateAppend({props: {email: invite.email, link: invite.url}, selected: 'inviteSent'})
- }
- const onSelectUser = useProfileState(s => s.dispatch.showUserProfile)
-
- const [inviteEmail, setInviteEmail] = React.useState('')
- const [inviteMessage, setInviteMessage] = React.useState('')
- const [showMessageField, setShowMessageField] = React.useState(false)
-
- React.useEffect(() => {
- onRefresh()
- }, [onRefresh])
-
- React.useEffect(() => {
- return () => {
- onClearError()
- }
- }, [error, onClearError])
-
- const handleChangeEmail = (email: string) => {
- setInviteEmail(email)
- setShowMessageField(showMessageField || email.length > 0)
- if (error) onClearError()
- }
-
- const invite = () => {
- onGenerateInvitation(inviteEmail, inviteMessage)
- }
-
- return (
-
- {!!error && (
-
-
-
- )}
-
-
-
- {showMessageField && (
-
- )}
-
-
- {pendingInvites.length > 0 && (
-
- Pending invites ({pendingInvites.length})
- {intersperseDividers(
- pendingInvites.map(invite => (
- onReclaimInvitation(id)}
- onSelectPendingInvite={invite => onSelectPendingInvite(invite)}
- />
- ))
- )}
-
- )}
-
- Accepted invites ({acceptedInvites.length})
- {intersperseDividers(
- acceptedInvites.map(invite => (
- onSelectUser(invite.username)}
- />
- ))
- )}
-
-
-
- )
-}
-
-function intersperseDividers(arr: Array) {
- return intersperseFn(i => , arr)
-}
-
-function PendingInviteItem({
- invite,
- onReclaimInvitation,
- onSelectPendingInvite,
-}: {
- invite: PendingInvite
- onReclaimInvitation: (id: string) => void
- onSelectPendingInvite: (invite: PendingInvite) => void
-}) {
- return (
-
- {invite.email ? (
-
- ) : (
-
- )}
-
- onReclaimInvitation(invite.id)}
- style={{color: Kb.Styles.globalColors.redDark}}
- >
- Reclaim
-
-
- )
-}
-
-function PendingEmailContent({
- invite,
- onSelectPendingInvite,
-}: {
- invite: PendingInvite
- onSelectPendingInvite: (invite: PendingInvite) => void
-}) {
- return (
-
-
-
- onSelectPendingInvite(invite)}>
- {invite.email}
-
-
- Invited {dateFns.format(dateFns.fromUnixTime(invite.created), 'MMM d, yyyy')}
-
-
-
- )
-}
-
-function PendingURLContent({invite}: {invite: PendingInvite}) {
- return (
-
-
-
- {invite.url}
-
-
- )
-}
-
-function AcceptedInviteItem(p: {invite: AcceptedInvite; onClick: () => void}) {
- const {invite, onClick} = p
- return (
-
-
-
-
-
-
- )
-}
-
-const styles = Kb.Styles.styleSheetCreate(() => ({
- container: {
- alignSelf: 'flex-start' as const,
- marginTop: Kb.Styles.globalMargins.small,
- minHeight: 269,
- width: 400,
- },
- inviteItem: {
- ...Kb.Styles.globalStyles.flexBoxRow,
- alignItems: 'center' as const,
- flexShrink: 0,
- height: 40,
- marginLeft: Kb.Styles.globalMargins.tiny,
- marginRight: Kb.Styles.globalMargins.tiny,
- },
-}))
-
-export default Invites
diff --git a/shared/settings/invites/index.native.tsx b/shared/settings/invites/index.native.tsx
deleted file mode 100644
index 0e65003e748d..000000000000
--- a/shared/settings/invites/index.native.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-function Invites() {
- return null
-}
-
-export default Invites
diff --git a/shared/settings/routes.tsx b/shared/settings/routes.tsx
index dead7baabb06..7f1f0232cfd8 100644
--- a/shared/settings/routes.tsx
+++ b/shared/settings/routes.tsx
@@ -48,7 +48,6 @@ export const sharedNewRoutes = {
screen: React.lazy(async () => import('./files')),
},
[Settings.settingsGitTab]: gitRoutes.gitRoot,
- [Settings.settingsInvitationsTab]: {screen: React.lazy(async () => import('./invites'))},
[Settings.settingsNotificationsTab]: {
getOptions: {title: 'Notifications'},
screen: React.lazy(async () => import('./notifications')),
@@ -66,7 +65,6 @@ export const sharedNewRoutes = {
getOptions: {title: 'Confirm'},
screen: React.lazy(async () => import('./db-nuke.confirm')),
},
- inviteSent: C.makeScreen(React.lazy(async () => import('./invite-generated'))),
keybaseLinkError: {screen: React.lazy(async () => import('../deeplinks/error'))},
makeIcons: {screen: React.lazy(async () => import('./make-icons.page'))},
removeDevice: devicesRoutes.deviceRevoke,
diff --git a/shared/settings/sub-nav/left-nav.tsx b/shared/settings/sub-nav/left-nav.tsx
index 6e7337a14961..041386f3f131 100644
--- a/shared/settings/sub-nav/left-nav.tsx
+++ b/shared/settings/sub-nav/left-nav.tsx
@@ -114,14 +114,6 @@ const LeftNav = (props: Props) => {
selected={props.selected === Settings.settingsFsTab}
onClick={props.onClick}
/>
- {!Kb.Styles.isTablet && (
-
- )}
- acceptedInvites: Array
- error: string
-}>
-
-const initialStore: Store = {
- acceptedInvites: [],
- error: '',
- pendingInvites: [],
-}
-
-export interface State extends Store {
- dispatch: {
- loadInvites: () => void
- reclaimInvite: (inviteId: string) => void
- resetError: () => void
- resetState: 'default'
- sendInvite: (email: string, message: string) => void
- }
-}
-
-export const useState = Z.createZustand((set, get) => {
- const dispatch: State['dispatch'] = {
- loadInvites: () => {
- const f = async () => {
- const json = await T.RPCGen.apiserverGetWithSessionRpcPromise(
- {
- args: [],
- endpoint: 'invitations_sent',
- },
- waitingKeySettingsGeneric
- )
- const results = JSON.parse(json.body) as
- | {
- invitations: Array<{
- assertion: string | undefined
- ctime: number
- email: string
- invitation_id: string
- short_code: string
- type: string
- uid: string
- username: string
- }>
- }
- | undefined
-
- const acceptedInvites: Array = []
- const pendingInvites: Array = []
-
- results?.invitations.forEach(i => {
- const invite: Invitation = {
- created: i.ctime,
- email: i.email,
- id: i.invitation_id,
- // type will get filled in later
- type: '',
- uid: i.uid,
- // First ten chars of invite code is sufficient
- url: 'keybase.io/inv/' + i.invitation_id.slice(0, 10),
- username: i.username,
- }
- // Here's an algorithm for interpreting invitation entries.
- // 1: username+uid => accepted invite, else
- // 2: email set => pending email invite, else
- // 3: pending invitation code invite
- if (i.username && i.uid) {
- invite.type = 'accepted'
- acceptedInvites.push(invite)
- } else {
- invite.type = 'pending'
- pendingInvites.push(invite)
- }
- })
- set(s => {
- s.acceptedInvites = acceptedInvites
- s.pendingInvites = pendingInvites
- })
- }
- ignorePromise(f())
- },
- reclaimInvite: inviteId => {
- const f = async () => {
- try {
- await T.RPCGen.apiserverPostRpcPromise(
- {
- args: [{key: 'invitation_id', value: inviteId}],
- endpoint: 'cancel_invitation',
- },
- waitingKeySettingsGeneric
- )
- } catch (e) {
- logger.warn('Error reclaiming an invite:', e)
- }
- get().dispatch.loadInvites()
- }
- ignorePromise(f())
- },
- resetError: () => {
- set(s => {
- s.error = ''
- })
- },
- resetState: 'default',
- sendInvite: (email, message) => {
- const f = async () => {
- try {
- const args = [{key: 'email', value: trim(email)}]
- if (message) {
- args.push({key: 'invitation_message', value: message})
- }
-
- const response = await T.RPCGen.apiserverPostRpcPromise(
- {args, endpoint: 'send_invitation'},
- waitingKeySettingsGeneric
- )
- const parsedBody = JSON.parse(response.body) as undefined | Partial<{invitation_id: string}>
- const invitationId = parsedBody?.invitation_id?.slice(0, 10) ?? ''
- if (!invitationId) return
- const link = 'keybase.io/inv/' + invitationId
- set(s => {
- s.error = ''
- })
- get().dispatch.loadInvites()
- navigateAppend({props: {email, link}, selected: 'inviteSent'})
- } catch (error) {
- if (!(error instanceof RPCError)) {
- return
- }
- logger.warn('Error sending an invite:', error)
- const msg = error.desc
- set(s => {
- s.error = msg
- })
- get().dispatch.loadInvites()
- }
- }
- ignorePromise(f())
- },
- }
- return {
- ...initialStore,
- dispatch,
- }
-})
diff --git a/shared/stores/signup.tsx b/shared/stores/signup.tsx
index c2bf965d4802..a73a84250abb 100644
--- a/shared/stores/signup.tsx
+++ b/shared/stores/signup.tsx
@@ -7,7 +7,7 @@ import * as Z from '@/util/zustand'
import logger from '@/logger'
import trim from 'lodash/trim'
import {RPCError} from '@/util/errors'
-import {isValidEmail, isValidName, isValidUsername} from '@/util/simple-validators'
+import {isValidUsername} from '@/util/simple-validators'
import {navigateAppend, navigateUp} from '@/constants/router'
import {useConfigState} from '@/stores/config'
@@ -50,13 +50,11 @@ export interface State extends Store {
onShowPermissionsPrompt?: (p: {justSignedUp?: boolean}) => void
}
checkDeviceName: (devicename: string) => void
- checkInviteCode: () => void
checkUsername: (username: string) => void
clearJustSignedUpEmail: () => void
goBackAndClearErrors: () => void
onEngineIncomingImpl: (action: EngineGen.Actions) => void
requestAutoInvite: (username?: string) => void
- requestInvite: (email: string, name: string) => void
resetState: () => void
restartSignup: () => void
setJustSignedUpEmail: (email: string) => void
@@ -78,8 +76,8 @@ export const useSignupState = Z.createZustand((set, get) => {
}
const {username, inviteCode, devicename} = get()
- if (!username || !inviteCode || !devicename) {
- logger.warn('Missing data during signup phase', username, inviteCode, devicename)
+ if (!username || !devicename) {
+ logger.warn('Missing data during signup phase', username, devicename)
throw new Error('Missing data for signup')
}
@@ -166,29 +164,6 @@ export const useSignupState = Z.createZustand((set, get) => {
}
ignorePromise(f())
},
- checkInviteCode: () => {
- const invitationCode = get().inviteCode
- const f = async () => {
- try {
- await T.RPCGen.signupCheckInvitationCodeRpcPromise({invitationCode}, S.waitingKeySignup)
- set(s => {
- s.signupError = undefined
- })
- if (noErrors()) {
- navigateUp()
- navigateAppend('signupEnterUsername')
- }
- } catch (error) {
- if (error instanceof RPCError) {
- const e = error
- set(s => {
- s.signupError = e
- })
- }
- }
- }
- ignorePromise(f())
- },
checkUsername: username => {
set(s => {
s.username = username
@@ -275,43 +250,13 @@ export const useSignupState = Z.createZustand((set, get) => {
set(s => {
s.inviteCode = inviteCode
})
- get().dispatch.checkInviteCode()
} catch {
set(s => {
s.inviteCode = ''
})
- navigateAppend('signupError')
- }
- }
- ignorePromise(f())
- },
- // shouldn't ever be used
- requestInvite: (email, name) => {
- set(s => {
- s.email = email
- s.emailError = isValidEmail(email)
- s.name = name
- s.nameError = isValidName(name)
- })
- const f = async () => {
- if (!noErrors()) {
- return
- }
- try {
- await T.RPCGen.signupInviteRequestRpcPromise(
- {email, fullname: name, notes: 'Requested through GUI app'},
- S.waitingKeySignup
- )
- // C.useRouterState.getState().dispatch.navigateAppend('signupRequestInviteSuccess')
- } catch (error) {
- if (error instanceof RPCError) {
- const emailError = `Sorry can't get an invite: ${error.desc}`
- set(s => {
- s.emailError = emailError
- s.nameError = ''
- })
- }
}
+ navigateUp()
+ navigateAppend('signupEnterUsername')
}
ignorePromise(f())
},