forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import React from 'react'
2import {View} from 'react-native'
3import {msg, Trans} from '@lingui/macro'
4import {useLingui} from '@lingui/react'
5import deepEqual from 'fast-deep-equal'
6
7import {logger} from '#/logger'
8import {usePostInteractionSettingsMutation} from '#/state/queries/post-interaction-settings'
9import {createPostgateRecord} from '#/state/queries/postgate/util'
10import {
11 usePreferencesQuery,
12 type UsePreferencesQueryResponse,
13} from '#/state/queries/preferences'
14import {
15 threadgateAllowUISettingToAllowRecordValue,
16 threadgateRecordToAllowUISetting,
17} from '#/state/queries/threadgate'
18import * as Toast from '#/view/com/util/Toast'
19import {atoms as a, useGutters} from '#/alf'
20import {Admonition} from '#/components/Admonition'
21import {PostInteractionSettingsForm} from '#/components/dialogs/PostInteractionSettingsDialog'
22import * as Layout from '#/components/Layout'
23import {Loader} from '#/components/Loader'
24
25export function Screen() {
26 const gutters = useGutters(['base'])
27 const {data: preferences} = usePreferencesQuery()
28 return (
29 <Layout.Screen testID="ModerationInteractionSettingsScreen">
30 <Layout.Header.Outer>
31 <Layout.Header.BackButton />
32 <Layout.Header.Content>
33 <Layout.Header.TitleText>
34 <Trans>Skeet Interaction Settings</Trans>
35 </Layout.Header.TitleText>
36 </Layout.Header.Content>
37 <Layout.Header.Slot />
38 </Layout.Header.Outer>
39 <Layout.Content>
40 <View style={[gutters, a.gap_xl]}>
41 <Admonition type="tip">
42 <Trans>
43 The following settings will be used as your defaults when creating
44 new skeets. You can edit these for a specific skeet from the
45 composer.
46 </Trans>
47 </Admonition>
48 {preferences ? (
49 <Inner preferences={preferences} />
50 ) : (
51 <View style={[gutters, a.justify_center, a.align_center]}>
52 <Loader size="xl" />
53 </View>
54 )}
55 </View>
56 </Layout.Content>
57 </Layout.Screen>
58 )
59}
60
61function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
62 const {_} = useLingui()
63 const {mutateAsync: setPostInteractionSettings, isPending} =
64 usePostInteractionSettingsMutation()
65 const [error, setError] = React.useState<string | undefined>(undefined)
66
67 const allowUI = React.useMemo(() => {
68 return threadgateRecordToAllowUISetting({
69 $type: 'app.bsky.feed.threadgate',
70 post: '',
71 createdAt: new Date().toString(),
72 allow: preferences.postInteractionSettings.threadgateAllowRules,
73 })
74 }, [preferences.postInteractionSettings.threadgateAllowRules])
75 const postgate = React.useMemo(() => {
76 return createPostgateRecord({
77 post: '',
78 embeddingRules:
79 preferences.postInteractionSettings.postgateEmbeddingRules,
80 })
81 }, [preferences.postInteractionSettings.postgateEmbeddingRules])
82
83 const [maybeEditedAllowUI, setAllowUI] = React.useState(allowUI)
84 const [maybeEditedPostgate, setEditedPostgate] = React.useState(postgate)
85
86 const wasEdited = React.useMemo(() => {
87 return (
88 !deepEqual(allowUI, maybeEditedAllowUI) ||
89 !deepEqual(postgate.embeddingRules, maybeEditedPostgate.embeddingRules)
90 )
91 }, [postgate, allowUI, maybeEditedAllowUI, maybeEditedPostgate])
92
93 const onSave = React.useCallback(async () => {
94 setError('')
95
96 try {
97 await setPostInteractionSettings({
98 threadgateAllowRules:
99 threadgateAllowUISettingToAllowRecordValue(maybeEditedAllowUI),
100 postgateEmbeddingRules: maybeEditedPostgate.embeddingRules ?? [],
101 })
102 Toast.show(_(msg({message: 'Settings saved', context: 'toast'})))
103 } catch (e: any) {
104 logger.error(`Failed to save post interaction settings`, {
105 source: 'ModerationInteractionSettingsScreen',
106 safeMessage: e.message,
107 })
108 setError(_(msg`Failed to save settings. Please try again.`))
109 }
110 }, [_, maybeEditedPostgate, maybeEditedAllowUI, setPostInteractionSettings])
111
112 return (
113 <>
114 <PostInteractionSettingsForm
115 canSave={wasEdited}
116 isSaving={isPending}
117 onSave={onSave}
118 postgate={maybeEditedPostgate}
119 onChangePostgate={setEditedPostgate}
120 threadgateAllowUISettings={maybeEditedAllowUI}
121 onChangeThreadgateAllowUISettings={setAllowUI}
122 />
123
124 {error && <Admonition type="error">{error}</Admonition>}
125 </>
126 )
127}