Modernise link warning dialog (#8243)
* add link warning dialog * add copy for if sharing * delete old modal * get web working
This commit is contained in:
+17
-11
@@ -24,6 +24,7 @@ import {Button, type ButtonProps} from '#/components/Button'
|
|||||||
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||||
import {Text, type TextProps} from '#/components/Typography'
|
import {Text, type TextProps} from '#/components/Typography'
|
||||||
import {router} from '#/routes'
|
import {router} from '#/routes'
|
||||||
|
import {useGlobalDialogsControlContext} from './dialogs/Context'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only available within a `Link`, since that inherits from `Button`.
|
* Only available within a `Link`, since that inherits from `Button`.
|
||||||
@@ -111,7 +112,8 @@ export function useLink({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isExternal = isExternalUrl(href)
|
const isExternal = isExternalUrl(href)
|
||||||
const {openModal, closeModal} = useModalControls()
|
const {closeModal} = useModalControls()
|
||||||
|
const {linkWarningDialogControl} = useGlobalDialogsControlContext()
|
||||||
const openLink = useOpenLink()
|
const openLink = useOpenLink()
|
||||||
|
|
||||||
const onPress = React.useCallback(
|
const onPress = React.useCallback(
|
||||||
@@ -132,10 +134,9 @@ export function useLink({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (requiresWarning) {
|
if (requiresWarning) {
|
||||||
openModal({
|
linkWarningDialogControl.open({
|
||||||
name: 'link-warning',
|
displayText,
|
||||||
text: displayText,
|
href,
|
||||||
href: href,
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (isExternal) {
|
if (isExternal) {
|
||||||
@@ -176,13 +177,13 @@ export function useLink({
|
|||||||
displayText,
|
displayText,
|
||||||
isExternal,
|
isExternal,
|
||||||
href,
|
href,
|
||||||
openModal,
|
|
||||||
openLink,
|
openLink,
|
||||||
closeModal,
|
closeModal,
|
||||||
action,
|
action,
|
||||||
navigation,
|
navigation,
|
||||||
overridePresentation,
|
overridePresentation,
|
||||||
shouldProxy,
|
shouldProxy,
|
||||||
|
linkWarningDialogControl,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -195,16 +196,21 @@ export function useLink({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (requiresWarning) {
|
if (requiresWarning) {
|
||||||
openModal({
|
linkWarningDialogControl.open({
|
||||||
name: 'link-warning',
|
displayText,
|
||||||
text: displayText,
|
href,
|
||||||
href: href,
|
|
||||||
share: true,
|
share: true,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
shareUrl(href)
|
shareUrl(href)
|
||||||
}
|
}
|
||||||
}, [disableMismatchWarning, displayText, href, isExternal, openModal])
|
}, [
|
||||||
|
disableMismatchWarning,
|
||||||
|
displayText,
|
||||||
|
href,
|
||||||
|
isExternal,
|
||||||
|
linkWarningDialogControl,
|
||||||
|
])
|
||||||
|
|
||||||
const onLongPress = React.useCallback(
|
const onLongPress = React.useCallback(
|
||||||
(e: GestureResponderEvent) => {
|
(e: GestureResponderEvent) => {
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ type ControlsContext = {
|
|||||||
signinDialogControl: Control
|
signinDialogControl: Control
|
||||||
inAppBrowserConsentControl: StatefulControl<string>
|
inAppBrowserConsentControl: StatefulControl<string>
|
||||||
emailDialogControl: StatefulControl<Screen>
|
emailDialogControl: StatefulControl<Screen>
|
||||||
|
linkWarningDialogControl: StatefulControl<{
|
||||||
|
href: string
|
||||||
|
displayText: string
|
||||||
|
share?: boolean
|
||||||
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
const ControlsContext = createContext<ControlsContext | null>(null)
|
const ControlsContext = createContext<ControlsContext | null>(null)
|
||||||
@@ -36,6 +41,11 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
const signinDialogControl = Dialog.useDialogControl()
|
const signinDialogControl = Dialog.useDialogControl()
|
||||||
const inAppBrowserConsentControl = useStatefulDialogControl<string>()
|
const inAppBrowserConsentControl = useStatefulDialogControl<string>()
|
||||||
const emailDialogControl = useStatefulDialogControl<Screen>()
|
const emailDialogControl = useStatefulDialogControl<Screen>()
|
||||||
|
const linkWarningDialogControl = useStatefulDialogControl<{
|
||||||
|
href: string
|
||||||
|
displayText: string
|
||||||
|
share?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
const ctx = useMemo<ControlsContext>(
|
const ctx = useMemo<ControlsContext>(
|
||||||
() => ({
|
() => ({
|
||||||
@@ -43,12 +53,14 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
signinDialogControl,
|
signinDialogControl,
|
||||||
inAppBrowserConsentControl,
|
inAppBrowserConsentControl,
|
||||||
emailDialogControl,
|
emailDialogControl,
|
||||||
|
linkWarningDialogControl,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
mutedWordsDialogControl,
|
mutedWordsDialogControl,
|
||||||
signinDialogControl,
|
signinDialogControl,
|
||||||
inAppBrowserConsentControl,
|
inAppBrowserConsentControl,
|
||||||
emailDialogControl,
|
emailDialogControl,
|
||||||
|
linkWarningDialogControl,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
import {useCallback, useMemo} from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
import {msg, Trans} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {useOpenLink} from '#/lib/hooks/useOpenLink'
|
||||||
|
import {shareUrl} from '#/lib/sharing'
|
||||||
|
import {isPossiblyAUrl, splitApexDomain} from '#/lib/strings/url-helpers'
|
||||||
|
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
|
||||||
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
|
import * as Dialog from '#/components/Dialog'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useGlobalDialogsControlContext} from './Context'
|
||||||
|
|
||||||
|
export function LinkWarningDialog() {
|
||||||
|
const {linkWarningDialogControl} = useGlobalDialogsControlContext()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog.Outer
|
||||||
|
control={linkWarningDialogControl.control}
|
||||||
|
nativeOptions={{preventExpansion: true}}
|
||||||
|
webOptions={{alignCenter: true}}
|
||||||
|
onClose={linkWarningDialogControl.clear}>
|
||||||
|
<Dialog.Handle />
|
||||||
|
<InAppBrowserConsentInner link={linkWarningDialogControl.value} />
|
||||||
|
</Dialog.Outer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function InAppBrowserConsentInner({
|
||||||
|
link,
|
||||||
|
}: {
|
||||||
|
link?: {href: string; displayText: string; share?: boolean}
|
||||||
|
}) {
|
||||||
|
const control = Dialog.useDialogContext()
|
||||||
|
const {_} = useLingui()
|
||||||
|
const t = useTheme()
|
||||||
|
const openLink = useOpenLink()
|
||||||
|
const {gtMobile} = useBreakpoints()
|
||||||
|
|
||||||
|
const potentiallyMisleading = useMemo(
|
||||||
|
() => link && isPossiblyAUrl(link.displayText),
|
||||||
|
[link],
|
||||||
|
)
|
||||||
|
|
||||||
|
const onPressVisit = useCallback(() => {
|
||||||
|
control.close(() => {
|
||||||
|
if (!link) return
|
||||||
|
if (link.share) {
|
||||||
|
shareUrl(link.href)
|
||||||
|
} else {
|
||||||
|
openLink(link.href, undefined, true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [control, link, openLink])
|
||||||
|
|
||||||
|
const onCancel = useCallback(() => {
|
||||||
|
control.close()
|
||||||
|
}, [control])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog.ScrollableInner
|
||||||
|
style={web({maxWidth: 450})}
|
||||||
|
label={
|
||||||
|
potentiallyMisleading
|
||||||
|
? _(msg`Potentially misleading link warning`)
|
||||||
|
: _(msg`Leaving Bluesky`)
|
||||||
|
}>
|
||||||
|
<View style={[a.gap_2xl]}>
|
||||||
|
<View style={[a.gap_sm]}>
|
||||||
|
<Text style={[a.font_heavy, a.text_2xl]}>
|
||||||
|
{potentiallyMisleading ? (
|
||||||
|
<Trans>Potentially misleading link</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>Leaving Bluesky</Trans>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
<Text style={[t.atoms.text_contrast_high, a.text_md, a.leading_snug]}>
|
||||||
|
<Trans>This link is taking you to the following website:</Trans>
|
||||||
|
</Text>
|
||||||
|
{link && <LinkBox href={link.href} />}
|
||||||
|
{potentiallyMisleading && (
|
||||||
|
<Text
|
||||||
|
style={[t.atoms.text_contrast_high, a.text_md, a.leading_snug]}>
|
||||||
|
<Trans>Make sure this is where you intend to go!</Trans>
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.flex_1,
|
||||||
|
a.gap_sm,
|
||||||
|
gtMobile && [a.flex_row_reverse, a.justify_start],
|
||||||
|
]}>
|
||||||
|
<Button
|
||||||
|
label={link?.share ? _(msg`Share link`) : _(msg`Visit site`)}
|
||||||
|
accessibilityHint={_(msg`Opens link ${link?.href ?? ''}`)}
|
||||||
|
onPress={onPressVisit}
|
||||||
|
size="large"
|
||||||
|
variant="solid"
|
||||||
|
color={potentiallyMisleading ? 'secondary_inverted' : 'primary'}>
|
||||||
|
<ButtonText>
|
||||||
|
{link?.share ? (
|
||||||
|
<Trans>Share link</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>Visit site</Trans>
|
||||||
|
)}
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
label={_(msg`Go back`)}
|
||||||
|
onPress={onCancel}
|
||||||
|
size="large"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary">
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Go back</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<Dialog.Close />
|
||||||
|
</Dialog.ScrollableInner>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function LinkBox({href}: {href: string}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const [scheme, hostname, rest] = useMemo(() => {
|
||||||
|
try {
|
||||||
|
const urlp = new URL(href)
|
||||||
|
const [subdomain, apexdomain] = splitApexDomain(urlp.hostname)
|
||||||
|
return [
|
||||||
|
urlp.protocol + '//' + subdomain,
|
||||||
|
apexdomain,
|
||||||
|
urlp.pathname.replace(/\/$/, '') + urlp.search + urlp.hash,
|
||||||
|
]
|
||||||
|
} catch {
|
||||||
|
return ['', href, '']
|
||||||
|
}
|
||||||
|
}, [href])
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
t.atoms.bg,
|
||||||
|
t.atoms.border_contrast_medium,
|
||||||
|
a.px_md,
|
||||||
|
{paddingVertical: 10},
|
||||||
|
a.rounded_sm,
|
||||||
|
a.border,
|
||||||
|
]}>
|
||||||
|
<Text style={[a.text_md, a.leading_snug, t.atoms.text_contrast_medium]}>
|
||||||
|
{scheme}
|
||||||
|
<Text style={[a.text_md, a.leading_snug, t.atoms.text, a.font_bold]}>
|
||||||
|
{hostname}
|
||||||
|
</Text>
|
||||||
|
{rest}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -43,13 +43,6 @@ export interface ChangePasswordModal {
|
|||||||
name: 'change-password'
|
name: 'change-password'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LinkWarningModal {
|
|
||||||
name: 'link-warning'
|
|
||||||
text: string
|
|
||||||
href: string
|
|
||||||
share?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Modal =
|
export type Modal =
|
||||||
// Account
|
// Account
|
||||||
| DeleteAccountModal
|
| DeleteAccountModal
|
||||||
@@ -67,9 +60,6 @@ export type Modal =
|
|||||||
| WaitlistModal
|
| WaitlistModal
|
||||||
| InviteCodesModal
|
| InviteCodesModal
|
||||||
|
|
||||||
// Generic
|
|
||||||
| LinkWarningModal
|
|
||||||
|
|
||||||
const ModalContext = React.createContext<{
|
const ModalContext = React.createContext<{
|
||||||
isModalActive: boolean
|
isModalActive: boolean
|
||||||
activeModals: Modal[]
|
activeModals: Modal[]
|
||||||
|
|||||||
@@ -1,180 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import {SafeAreaView, StyleSheet, View} from 'react-native'
|
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
|
||||||
import {msg, Trans} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
|
|
||||||
import {useOpenLink} from '#/lib/hooks/useOpenLink'
|
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
|
||||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
|
||||||
import {shareUrl} from '#/lib/sharing'
|
|
||||||
import {isPossiblyAUrl, splitApexDomain} from '#/lib/strings/url-helpers'
|
|
||||||
import {colors, s} from '#/lib/styles'
|
|
||||||
import {isWeb} from '#/platform/detection'
|
|
||||||
import {useModalControls} from '#/state/modals'
|
|
||||||
import {Button} from '#/view/com/util/forms/Button'
|
|
||||||
import {Text} from '#/view/com/util/text/Text'
|
|
||||||
import {ScrollView} from './util'
|
|
||||||
|
|
||||||
export const snapPoints = ['50%']
|
|
||||||
|
|
||||||
export function Component({
|
|
||||||
text,
|
|
||||||
href,
|
|
||||||
share,
|
|
||||||
}: {
|
|
||||||
text: string
|
|
||||||
href: string
|
|
||||||
share?: boolean
|
|
||||||
}) {
|
|
||||||
const pal = usePalette('default')
|
|
||||||
const {closeModal} = useModalControls()
|
|
||||||
const {isMobile} = useWebMediaQueries()
|
|
||||||
const {_} = useLingui()
|
|
||||||
const potentiallyMisleading = isPossiblyAUrl(text)
|
|
||||||
const openLink = useOpenLink()
|
|
||||||
|
|
||||||
const onPressVisit = () => {
|
|
||||||
closeModal()
|
|
||||||
if (share) {
|
|
||||||
shareUrl(href)
|
|
||||||
} else {
|
|
||||||
openLink(href, false, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SafeAreaView style={[s.flex1, pal.view]}>
|
|
||||||
<ScrollView
|
|
||||||
testID="linkWarningModal"
|
|
||||||
style={[s.flex1, isMobile && {paddingHorizontal: 18}]}>
|
|
||||||
<View style={styles.titleSection}>
|
|
||||||
{potentiallyMisleading ? (
|
|
||||||
<>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon="circle-exclamation"
|
|
||||||
color={pal.colors.text}
|
|
||||||
size={18}
|
|
||||||
/>
|
|
||||||
<Text type="title-lg" style={[pal.text, styles.title]}>
|
|
||||||
<Trans>Potentially Misleading Link</Trans>
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Text type="title-lg" style={[pal.text, styles.title]}>
|
|
||||||
<Trans>Leaving Bluesky</Trans>
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{gap: 10}}>
|
|
||||||
<Text type="lg" style={pal.text}>
|
|
||||||
<Trans>This link is taking you to the following website:</Trans>
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<LinkBox href={href} />
|
|
||||||
|
|
||||||
{potentiallyMisleading && (
|
|
||||||
<Text type="lg" style={pal.text}>
|
|
||||||
<Trans>Make sure this is where you intend to go!</Trans>
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={[styles.btnContainer, isMobile && {paddingBottom: 40}]}>
|
|
||||||
<Button
|
|
||||||
testID="confirmBtn"
|
|
||||||
type="primary"
|
|
||||||
onPress={onPressVisit}
|
|
||||||
accessibilityLabel={share ? _(msg`Share Link`) : _(msg`Visit Site`)}
|
|
||||||
accessibilityHint={
|
|
||||||
share
|
|
||||||
? _(msg`Shares the linked website`)
|
|
||||||
: _(msg`Opens the linked website`)
|
|
||||||
}
|
|
||||||
label={share ? _(msg`Share Link`) : _(msg`Visit Site`)}
|
|
||||||
labelContainerStyle={{justifyContent: 'center', padding: 4}}
|
|
||||||
labelStyle={[s.f18]}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
testID="cancelBtn"
|
|
||||||
type="default"
|
|
||||||
onPress={() => {
|
|
||||||
closeModal()
|
|
||||||
}}
|
|
||||||
accessibilityLabel={_(msg`Cancel`)}
|
|
||||||
accessibilityHint={_(msg`Cancels opening the linked website`)}
|
|
||||||
label={_(msg`Cancel`)}
|
|
||||||
labelContainerStyle={{justifyContent: 'center', padding: 4}}
|
|
||||||
labelStyle={[s.f18]}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
</SafeAreaView>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function LinkBox({href}: {href: string}) {
|
|
||||||
const pal = usePalette('default')
|
|
||||||
const [scheme, hostname, rest] = React.useMemo(() => {
|
|
||||||
try {
|
|
||||||
const urlp = new URL(href)
|
|
||||||
const [subdomain, apexdomain] = splitApexDomain(urlp.hostname)
|
|
||||||
return [
|
|
||||||
urlp.protocol + '//' + subdomain,
|
|
||||||
apexdomain,
|
|
||||||
urlp.pathname + urlp.search + urlp.hash,
|
|
||||||
]
|
|
||||||
} catch {
|
|
||||||
return ['', href, '']
|
|
||||||
}
|
|
||||||
}, [href])
|
|
||||||
return (
|
|
||||||
<View style={[pal.view, pal.border, styles.linkBox]}>
|
|
||||||
<Text type="lg" style={pal.textLight}>
|
|
||||||
{scheme}
|
|
||||||
<Text type="lg-bold" style={pal.text}>
|
|
||||||
{hostname}
|
|
||||||
</Text>
|
|
||||||
{rest}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
paddingBottom: isWeb ? 0 : 40,
|
|
||||||
},
|
|
||||||
titleSection: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 6,
|
|
||||||
paddingTop: isWeb ? 0 : 4,
|
|
||||||
paddingBottom: isWeb ? 14 : 10,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
textAlign: 'center',
|
|
||||||
fontWeight: '600',
|
|
||||||
},
|
|
||||||
linkBox: {
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
paddingVertical: 10,
|
|
||||||
borderRadius: 6,
|
|
||||||
borderWidth: 1,
|
|
||||||
},
|
|
||||||
btn: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
borderRadius: 32,
|
|
||||||
padding: 14,
|
|
||||||
backgroundColor: colors.blue3,
|
|
||||||
},
|
|
||||||
btnContainer: {
|
|
||||||
paddingTop: 20,
|
|
||||||
gap: 6,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -13,7 +13,6 @@ import * as DeleteAccountModal from './DeleteAccount'
|
|||||||
import * as InviteCodesModal from './InviteCodes'
|
import * as InviteCodesModal from './InviteCodes'
|
||||||
import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
|
import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
|
||||||
import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
|
import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
|
||||||
import * as LinkWarningModal from './LinkWarning'
|
|
||||||
import * as UserAddRemoveListsModal from './UserAddRemoveLists'
|
import * as UserAddRemoveListsModal from './UserAddRemoveLists'
|
||||||
|
|
||||||
const DEFAULT_SNAPPOINTS = ['90%']
|
const DEFAULT_SNAPPOINTS = ['90%']
|
||||||
@@ -68,9 +67,6 @@ export function ModalsContainer() {
|
|||||||
} else if (activeModal?.name === 'change-password') {
|
} else if (activeModal?.name === 'change-password') {
|
||||||
snapPoints = ChangePasswordModal.snapPoints
|
snapPoints = ChangePasswordModal.snapPoints
|
||||||
element = <ChangePasswordModal.Component />
|
element = <ChangePasswordModal.Component />
|
||||||
} else if (activeModal?.name === 'link-warning') {
|
|
||||||
snapPoints = LinkWarningModal.snapPoints
|
|
||||||
element = <LinkWarningModal.Component {...activeModal} />
|
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import * as DeleteAccountModal from './DeleteAccount'
|
|||||||
import * as InviteCodesModal from './InviteCodes'
|
import * as InviteCodesModal from './InviteCodes'
|
||||||
import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
|
import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
|
||||||
import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
|
import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
|
||||||
import * as LinkWarningModal from './LinkWarning'
|
|
||||||
import * as UserAddRemoveLists from './UserAddRemoveLists'
|
import * as UserAddRemoveLists from './UserAddRemoveLists'
|
||||||
|
|
||||||
export function ModalsContainer() {
|
export function ModalsContainer() {
|
||||||
@@ -65,8 +64,6 @@ function Modal({modal}: {modal: ModalIface}) {
|
|||||||
element = <PostLanguagesSettingsModal.Component />
|
element = <PostLanguagesSettingsModal.Component />
|
||||||
} else if (modal.name === 'change-password') {
|
} else if (modal.name === 'change-password') {
|
||||||
element = <ChangePasswordModal.Component />
|
element = <ChangePasswordModal.Component />
|
||||||
} else if (modal.name === 'link-warning') {
|
|
||||||
element = <LinkWarningModal.Component {...modal} />
|
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import {emitSoftReset} from '#/state/events'
|
|||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
import {WebAuxClickWrapper} from '#/view/com/util/WebAuxClickWrapper'
|
import {WebAuxClickWrapper} from '#/view/com/util/WebAuxClickWrapper'
|
||||||
import {useTheme} from '#/alf'
|
import {useTheme} from '#/alf'
|
||||||
|
import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
|
||||||
import {router} from '../../../routes'
|
import {router} from '../../../routes'
|
||||||
import {PressableWithHover} from './PressableWithHover'
|
import {PressableWithHover} from './PressableWithHover'
|
||||||
import {Text} from './text/Text'
|
import {Text} from './text/Text'
|
||||||
@@ -189,7 +190,8 @@ export const TextLink = memo(function TextLink({
|
|||||||
onBeforePress?: () => void
|
onBeforePress?: () => void
|
||||||
} & TextProps) {
|
} & TextProps) {
|
||||||
const navigation = useNavigationDeduped()
|
const navigation = useNavigationDeduped()
|
||||||
const {openModal, closeModal} = useModalControls()
|
const {closeModal} = useModalControls()
|
||||||
|
const {linkWarningDialogControl} = useGlobalDialogsControlContext()
|
||||||
const openLink = useOpenLink()
|
const openLink = useOpenLink()
|
||||||
|
|
||||||
if (!disableMismatchWarning && typeof text !== 'string') {
|
if (!disableMismatchWarning && typeof text !== 'string') {
|
||||||
@@ -211,9 +213,8 @@ export const TextLink = memo(function TextLink({
|
|||||||
linkRequiresWarning(href, typeof text === 'string' ? text : '')
|
linkRequiresWarning(href, typeof text === 'string' ? text : '')
|
||||||
if (requiresWarning) {
|
if (requiresWarning) {
|
||||||
e?.preventDefault?.()
|
e?.preventDefault?.()
|
||||||
openModal({
|
linkWarningDialogControl.open({
|
||||||
name: 'link-warning',
|
displayText: typeof text === 'string' ? text : '',
|
||||||
text: typeof text === 'string' ? text : '',
|
|
||||||
href,
|
href,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -245,13 +246,13 @@ export const TextLink = memo(function TextLink({
|
|||||||
onBeforePress,
|
onBeforePress,
|
||||||
onPressProp,
|
onPressProp,
|
||||||
closeModal,
|
closeModal,
|
||||||
openModal,
|
|
||||||
navigation,
|
navigation,
|
||||||
href,
|
href,
|
||||||
text,
|
text,
|
||||||
disableMismatchWarning,
|
disableMismatchWarning,
|
||||||
navigationAction,
|
navigationAction,
|
||||||
openLink,
|
openLink,
|
||||||
|
linkWarningDialogControl,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
const hrefAttrs = useMemo(() => {
|
const hrefAttrs = useMemo(() => {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {atoms as a, select, useTheme} from '#/alf'
|
|||||||
import {setSystemUITheme} from '#/alf/util/systemUI'
|
import {setSystemUITheme} from '#/alf/util/systemUI'
|
||||||
import {EmailDialog} from '#/components/dialogs/EmailDialog'
|
import {EmailDialog} from '#/components/dialogs/EmailDialog'
|
||||||
import {InAppBrowserConsentDialog} from '#/components/dialogs/InAppBrowserConsent'
|
import {InAppBrowserConsentDialog} from '#/components/dialogs/InAppBrowserConsent'
|
||||||
|
import {LinkWarningDialog} from '#/components/dialogs/LinkWarning'
|
||||||
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
|
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
|
||||||
import {SigninDialog} from '#/components/dialogs/Signin'
|
import {SigninDialog} from '#/components/dialogs/Signin'
|
||||||
import {Outlet as PortalOutlet} from '#/components/Portal'
|
import {Outlet as PortalOutlet} from '#/components/Portal'
|
||||||
@@ -155,6 +156,7 @@ function ShellInner() {
|
|||||||
<SigninDialog />
|
<SigninDialog />
|
||||||
<EmailDialog />
|
<EmailDialog />
|
||||||
<InAppBrowserConsentDialog />
|
<InAppBrowserConsentDialog />
|
||||||
|
<LinkWarningDialog />
|
||||||
<Lightbox />
|
<Lightbox />
|
||||||
<PortalOutlet />
|
<PortalOutlet />
|
||||||
<BottomSheetOutlet />
|
<BottomSheetOutlet />
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {ModalsContainer} from '#/view/com/modals/Modal'
|
|||||||
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
||||||
import {atoms as a, select, useTheme} from '#/alf'
|
import {atoms as a, select, useTheme} from '#/alf'
|
||||||
import {EmailDialog} from '#/components/dialogs/EmailDialog'
|
import {EmailDialog} from '#/components/dialogs/EmailDialog'
|
||||||
|
import {LinkWarningDialog} from '#/components/dialogs/LinkWarning'
|
||||||
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
|
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
|
||||||
import {SigninDialog} from '#/components/dialogs/Signin'
|
import {SigninDialog} from '#/components/dialogs/Signin'
|
||||||
import {Outlet as PortalOutlet} from '#/components/Portal'
|
import {Outlet as PortalOutlet} from '#/components/Portal'
|
||||||
@@ -69,6 +70,7 @@ function ShellInner() {
|
|||||||
<MutedWordsDialog />
|
<MutedWordsDialog />
|
||||||
<SigninDialog />
|
<SigninDialog />
|
||||||
<EmailDialog />
|
<EmailDialog />
|
||||||
|
<LinkWarningDialog />
|
||||||
<Lightbox />
|
<Lightbox />
|
||||||
<PortalOutlet />
|
<PortalOutlet />
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user