@planningcenter/chat-react-native 3.24.4 → 3.25.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/conversations/conversation_actions.js +3 -3
- package/build/components/conversations/conversation_actions.js.map +1 -1
- package/build/components/conversations/conversations.d.ts.map +1 -1
- package/build/components/conversations/conversations.js +1 -0
- package/build/components/conversations/conversations.js.map +1 -1
- package/build/hooks/use_conversation.d.ts.map +1 -1
- package/build/hooks/use_conversation.js +13 -1
- package/build/hooks/use_conversation.js.map +1 -1
- package/build/hooks/use_conversation_membership.d.ts +5 -0
- package/build/hooks/use_conversation_membership.d.ts.map +1 -0
- package/build/hooks/use_conversation_membership.js +63 -0
- package/build/hooks/use_conversation_membership.js.map +1 -0
- package/build/hooks/use_conversations_actions.d.ts.map +1 -1
- package/build/hooks/use_conversations_actions.js +4 -0
- package/build/hooks/use_conversations_actions.js.map +1 -1
- package/build/hooks/use_features.d.ts +1 -0
- package/build/hooks/use_features.d.ts.map +1 -1
- package/build/hooks/use_features.js +1 -0
- package/build/hooks/use_features.js.map +1 -1
- package/build/navigation/index.d.ts +10 -0
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +12 -2
- package/build/navigation/index.js.map +1 -1
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +50 -16
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_notification_level_select_screen.d.ts +8 -0
- package/build/screens/conversation_notification_level_select_screen.d.ts.map +1 -0
- package/build/screens/conversation_notification_level_select_screen.js +49 -0
- package/build/screens/conversation_notification_level_select_screen.js.map +1 -0
- package/build/screens/conversation_screen.d.ts +3 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +16 -5
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/group_notification_level_select_screen.d.ts +8 -0
- package/build/screens/group_notification_level_select_screen.d.ts.map +1 -0
- package/build/screens/group_notification_level_select_screen.js +40 -0
- package/build/screens/group_notification_level_select_screen.js.map +1 -0
- package/build/screens/group_notification_settings_screen.d.ts.map +1 -1
- package/build/screens/group_notification_settings_screen.js +30 -17
- package/build/screens/group_notification_settings_screen.js.map +1 -1
- package/build/screens/notification_settings/hooks/groups.d.ts +6 -5
- package/build/screens/notification_settings/hooks/groups.d.ts.map +1 -1
- package/build/screens/notification_settings/hooks/groups.js +63 -36
- package/build/screens/notification_settings/hooks/groups.js.map +1 -1
- package/build/screens/notification_settings_screen.d.ts.map +1 -1
- package/build/screens/notification_settings_screen.js +25 -11
- package/build/screens/notification_settings_screen.js.map +1 -1
- package/build/types/resources/conversation.d.ts +2 -3
- package/build/types/resources/conversation.d.ts.map +1 -1
- package/build/types/resources/conversation.js.map +1 -1
- package/build/types/resources/conversation_membership.d.ts +16 -0
- package/build/types/resources/conversation_membership.d.ts.map +1 -0
- package/build/types/resources/conversation_membership.js +2 -0
- package/build/types/resources/conversation_membership.js.map +1 -0
- package/build/types/resources/group_membership.d.ts +7 -0
- package/build/types/resources/group_membership.d.ts.map +1 -1
- package/build/types/resources/group_membership.js.map +1 -1
- package/build/types/resources/index.d.ts +1 -0
- package/build/types/resources/index.d.ts.map +1 -1
- package/build/types/resources/index.js +1 -0
- package/build/types/resources/index.js.map +1 -1
- package/build/utils/deep_snake_case_keys.d.ts +4 -0
- package/build/utils/deep_snake_case_keys.d.ts.map +1 -0
- package/build/utils/deep_snake_case_keys.js +13 -0
- package/build/utils/deep_snake_case_keys.js.map +1 -0
- package/package.json +2 -2
- package/src/components/conversations/conversation_actions.tsx +3 -3
- package/src/components/conversations/conversations.tsx +1 -0
- package/src/hooks/use_conversation.ts +13 -1
- package/src/hooks/use_conversation_membership.ts +91 -0
- package/src/hooks/use_conversations_actions.ts +4 -0
- package/src/hooks/use_features.ts +1 -0
- package/src/navigation/index.tsx +19 -1
- package/src/screens/conversation_details_screen.tsx +87 -22
- package/src/screens/conversation_notification_level_select_screen.tsx +73 -0
- package/src/screens/conversation_screen.tsx +18 -4
- package/src/screens/group_notification_level_select_screen.tsx +62 -0
- package/src/screens/group_notification_settings_screen.tsx +53 -18
- package/src/screens/notification_settings/hooks/groups.ts +76 -37
- package/src/screens/notification_settings_screen.tsx +24 -21
- package/src/types/resources/conversation.ts +2 -3
- package/src/types/resources/conversation_membership.ts +17 -0
- package/src/types/resources/group_membership.ts +7 -0
- package/src/types/resources/index.ts +1 -0
- package/src/utils/deep_snake_case_keys.ts +16 -0
|
@@ -1,25 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HeaderTitle as ElementsHeaderTitle,
|
|
3
|
+
HeaderTitleProps,
|
|
4
|
+
PlatformPressable,
|
|
5
|
+
} from '@react-navigation/elements'
|
|
1
6
|
import { StackActions, StaticScreenProps, useNavigation } from '@react-navigation/native'
|
|
2
7
|
import React, {
|
|
3
8
|
useCallback,
|
|
4
9
|
useEffect,
|
|
10
|
+
useRef,
|
|
5
11
|
useState,
|
|
6
|
-
type SetStateAction,
|
|
7
12
|
type Dispatch,
|
|
8
13
|
type ReactNode,
|
|
9
|
-
|
|
14
|
+
type SetStateAction,
|
|
10
15
|
} from 'react'
|
|
11
16
|
import {
|
|
17
|
+
Alert,
|
|
12
18
|
FlatList,
|
|
19
|
+
Platform,
|
|
20
|
+
Pressable,
|
|
13
21
|
StyleSheet,
|
|
14
22
|
TextInput,
|
|
15
23
|
View,
|
|
16
|
-
type ViewStyle,
|
|
17
24
|
type ViewProps,
|
|
18
|
-
|
|
19
|
-
Alert,
|
|
20
|
-
Platform,
|
|
25
|
+
type ViewStyle,
|
|
21
26
|
} from 'react-native'
|
|
22
|
-
import { HeaderTitle as ElementsHeaderTitle, HeaderTitleProps } from '@react-navigation/elements'
|
|
23
27
|
import {
|
|
24
28
|
Badge,
|
|
25
29
|
ChildNotice,
|
|
@@ -31,6 +35,8 @@ import {
|
|
|
31
35
|
TextButton,
|
|
32
36
|
type TextStyle,
|
|
33
37
|
} from '../components'
|
|
38
|
+
import { HeaderTextButton } from '../components/display/platform_modal_header_buttons'
|
|
39
|
+
import { ButtonAppearanceUnion } from '../components/display/utils/button_colors'
|
|
34
40
|
import { useSuspensePaginator, useTheme } from '../hooks'
|
|
35
41
|
import {
|
|
36
42
|
useConversation,
|
|
@@ -39,14 +45,11 @@ import {
|
|
|
39
45
|
useConversationMute,
|
|
40
46
|
useConversationUpdate,
|
|
41
47
|
} from '../hooks/use_conversation'
|
|
48
|
+
|
|
49
|
+
import { availableFeatures, useFeatures } from '../hooks/use_features'
|
|
42
50
|
import { MemberResource, isDefined } from '../types'
|
|
43
|
-
import { HeaderTextButton } from '../components/display/platform_modal_header_buttons'
|
|
44
|
-
import { tokens } from '../vendor/tapestry/tokens'
|
|
45
|
-
import { ButtonAppearanceUnion } from '../components/display/utils/button_colors'
|
|
46
51
|
import { GroupResource } from '../types/resources/group_resource'
|
|
47
|
-
import {
|
|
48
|
-
import { availableFeatures } from '../hooks/use_features'
|
|
49
|
-
|
|
52
|
+
import { tokens } from '../vendor/tapestry/tokens'
|
|
50
53
|
// =========================================
|
|
51
54
|
// ====== Factory Constants & Types ========
|
|
52
55
|
// =========================================
|
|
@@ -56,6 +59,7 @@ enum SectionTypes {
|
|
|
56
59
|
hidden,
|
|
57
60
|
members,
|
|
58
61
|
loadingMembers,
|
|
62
|
+
navigableSetting,
|
|
59
63
|
setting,
|
|
60
64
|
view,
|
|
61
65
|
}
|
|
@@ -64,6 +68,7 @@ type SectionListData = Array<
|
|
|
64
68
|
| DataItem<{ title: string }, SectionTypes.header>
|
|
65
69
|
| DataItem<MemberResource, SectionTypes.members>
|
|
66
70
|
| DataItem<any, SectionTypes.loadingMembers>
|
|
71
|
+
| DataItem<NavigableSettingRowProps, SectionTypes.navigableSetting>
|
|
67
72
|
| DataItem<ViewProps, SectionTypes.view>
|
|
68
73
|
| DataItem<SettingRowProps, SectionTypes.setting>
|
|
69
74
|
| DataItem<any, SectionTypes.hidden>
|
|
@@ -91,16 +96,20 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
|
|
|
91
96
|
|
|
92
97
|
const { data: conversation } = useConversation(route.params)
|
|
93
98
|
const [title, setTitle] = useState(conversation.title)
|
|
94
|
-
const {
|
|
99
|
+
const { conversation_id } = route.params
|
|
95
100
|
const { repliesDisabled, setRepliesDisabled } = useConversationDisableReplies(route.params)
|
|
96
101
|
const { mutate: saveTitle } = useConversationUpdate(route.params)
|
|
97
102
|
const { mutate: deleteConversation } = useConversationDelete(route.params)
|
|
98
103
|
const { featureEnabled } = useFeatures()
|
|
99
104
|
const repliesEnabled = featureEnabled(availableFeatures.threaded_replies)
|
|
105
|
+
const granularNotificationsEnabled = featureEnabled(availableFeatures.granular_notifications_ui)
|
|
106
|
+
const { muted, setMuted } = useConversationMute({ conversation_id })
|
|
100
107
|
|
|
101
108
|
const trimmedTitle = title.trim()
|
|
102
109
|
const emptyTitle = trimmedTitle === '' || title === null
|
|
103
110
|
|
|
111
|
+
const notificationLevelDescription =
|
|
112
|
+
conversation?.conversationMembership?.notificationLevelDescription
|
|
104
113
|
const canUpdate = conversation.memberAbility?.canUpdate || false
|
|
105
114
|
const canDelete = conversation.memberAbility?.canDelete || false
|
|
106
115
|
const isLeader = conversation.memberAbility?.leader || false
|
|
@@ -243,14 +252,25 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
|
|
|
243
252
|
showBottomBorder: true,
|
|
244
253
|
sectionInnerStyle: styles.sectionInnerHeaderWithBottomBorder,
|
|
245
254
|
},
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
255
|
+
granularNotificationsEnabled
|
|
256
|
+
? {
|
|
257
|
+
type: SectionTypes.navigableSetting,
|
|
258
|
+
data: {
|
|
259
|
+
title: 'Notifications',
|
|
260
|
+
subtitle: notificationLevelDescription,
|
|
261
|
+
onPress: () =>
|
|
262
|
+
navigation.navigate('ConversationNotificationLevelSelect', { conversation_id }),
|
|
263
|
+
},
|
|
264
|
+
showBottomBorder: true,
|
|
265
|
+
}
|
|
266
|
+
: {
|
|
267
|
+
type: SectionTypes.setting,
|
|
268
|
+
data: {
|
|
269
|
+
title: 'Mute',
|
|
270
|
+
rightItem: <Switch value={muted} onValueChange={value => setMuted(value)} />,
|
|
271
|
+
},
|
|
272
|
+
showBottomBorder: true,
|
|
273
|
+
},
|
|
254
274
|
{
|
|
255
275
|
type: canUpdate ? SectionTypes.setting : SectionTypes.hidden,
|
|
256
276
|
data: {
|
|
@@ -350,6 +370,18 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
|
|
|
350
370
|
<Text>Loading more...</Text>
|
|
351
371
|
</ListSection>
|
|
352
372
|
)
|
|
373
|
+
case SectionTypes.navigableSetting:
|
|
374
|
+
return (
|
|
375
|
+
<ListSection
|
|
376
|
+
isStart={isStart}
|
|
377
|
+
isEnd={isEnd}
|
|
378
|
+
showBottomBorder={item?.showBottomBorder}
|
|
379
|
+
outerStyle={item?.sectionOuterStyle}
|
|
380
|
+
innerStyle={item?.sectionInnerStyle}
|
|
381
|
+
>
|
|
382
|
+
<NavigableSettingRow {...item.data} />
|
|
383
|
+
</ListSection>
|
|
384
|
+
)
|
|
353
385
|
case SectionTypes.setting:
|
|
354
386
|
return (
|
|
355
387
|
<ListSection
|
|
@@ -459,6 +491,12 @@ function TitleInput({ canUpdate, title, setTitle, style, isEmpty }: InputProps)
|
|
|
459
491
|
)
|
|
460
492
|
}
|
|
461
493
|
|
|
494
|
+
interface NavigableSettingRowProps {
|
|
495
|
+
title: string
|
|
496
|
+
subtitle?: string
|
|
497
|
+
onPress: () => void
|
|
498
|
+
}
|
|
499
|
+
|
|
462
500
|
interface SettingRowProps {
|
|
463
501
|
title: string
|
|
464
502
|
style?: ViewStyle
|
|
@@ -510,6 +548,30 @@ function SettingRow({
|
|
|
510
548
|
)
|
|
511
549
|
}
|
|
512
550
|
|
|
551
|
+
function NavigableSettingRow({ title, subtitle, onPress }: NavigableSettingRowProps) {
|
|
552
|
+
const styles = useStyles()
|
|
553
|
+
return (
|
|
554
|
+
<PlatformPressable onPress={onPress} accessibilityRole="button">
|
|
555
|
+
<View style={styles.settingRow}>
|
|
556
|
+
<View style={styles.settingRowContent}>
|
|
557
|
+
<Text variant="plain" style={styles.settingRowText}>
|
|
558
|
+
{title}
|
|
559
|
+
</Text>
|
|
560
|
+
{Boolean(subtitle) && <Text variant="footnote">{subtitle}</Text>}
|
|
561
|
+
</View>
|
|
562
|
+
{Platform.OS === 'ios' && (
|
|
563
|
+
<Icon
|
|
564
|
+
name="general.rightChevron"
|
|
565
|
+
size={16}
|
|
566
|
+
style={styles.navigableSettingChevron}
|
|
567
|
+
accessibilityElementsHidden
|
|
568
|
+
/>
|
|
569
|
+
)}
|
|
570
|
+
</View>
|
|
571
|
+
</PlatformPressable>
|
|
572
|
+
)
|
|
573
|
+
}
|
|
574
|
+
|
|
513
575
|
function TeamsGroup({ teams }: { teams: GroupResource[] }) {
|
|
514
576
|
const styles = useStyles()
|
|
515
577
|
|
|
@@ -628,6 +690,9 @@ const useStyles = ({ isStart, isEnd }: { isStart?: boolean; isEnd?: boolean } =
|
|
|
628
690
|
settingRowText: {
|
|
629
691
|
lineHeight: 20,
|
|
630
692
|
},
|
|
693
|
+
navigableSettingChevron: {
|
|
694
|
+
color: colors.iconColorDefaultDisabled,
|
|
695
|
+
},
|
|
631
696
|
teamGroup: {
|
|
632
697
|
flexDirection: 'row',
|
|
633
698
|
gap: 4,
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { StyleSheet } from 'react-native'
|
|
4
|
+
import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'
|
|
5
|
+
import { PressableRow } from '../components'
|
|
6
|
+
import { useTheme } from '../hooks'
|
|
7
|
+
import { useConversation } from '../hooks/use_conversation'
|
|
8
|
+
import { useConversationMembershipUpdate } from '../hooks/use_conversation_membership'
|
|
9
|
+
import { NotificationLevelValue } from '../types'
|
|
10
|
+
|
|
11
|
+
export const ConversationNotificationLevelSelectScreenOptions = getFormSheetScreenOptions({
|
|
12
|
+
headerTitle: 'Notification level',
|
|
13
|
+
sheetAllowedDetents: [0.35],
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export type ConversationNotificationLevelSelectScreenProps = StaticScreenProps<{
|
|
17
|
+
conversation_id: number
|
|
18
|
+
}>
|
|
19
|
+
|
|
20
|
+
export function ConversationNotificationLevelSelectScreen({
|
|
21
|
+
route,
|
|
22
|
+
}: ConversationNotificationLevelSelectScreenProps) {
|
|
23
|
+
const { conversation_id } = route.params
|
|
24
|
+
const navigation = useNavigation()
|
|
25
|
+
const styles = useStyles()
|
|
26
|
+
const { colors } = useTheme()
|
|
27
|
+
const { data: conversation } = useConversation({ conversation_id })
|
|
28
|
+
const { mutate: updateNotificationLevel } = useConversationMembershipUpdate({ conversation_id })
|
|
29
|
+
|
|
30
|
+
const notificationLevel = conversation.conversationMembership?.notificationLevel
|
|
31
|
+
const notificationLevelOptions =
|
|
32
|
+
conversation.conversationMembership?.notificationLevelOptions ?? []
|
|
33
|
+
|
|
34
|
+
const handleSelect = (value: NotificationLevelValue, isActive: boolean) => {
|
|
35
|
+
if (!isActive) {
|
|
36
|
+
const muted = value === 'nothing'
|
|
37
|
+
updateNotificationLevel({
|
|
38
|
+
muted,
|
|
39
|
+
notificationLevel: value as typeof notificationLevel,
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
navigation.goBack()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<FormSheet.Root contentStyle={styles.content}>
|
|
47
|
+
{notificationLevelOptions.map(option => {
|
|
48
|
+
const isActive = option.enabled
|
|
49
|
+
return (
|
|
50
|
+
<PressableRow
|
|
51
|
+
key={option.value}
|
|
52
|
+
text={option.description}
|
|
53
|
+
isActive={isActive}
|
|
54
|
+
onPress={() => handleSelect(option.value, isActive)}
|
|
55
|
+
iconColor={colors.statusSuccessIcon}
|
|
56
|
+
style={styles.row}
|
|
57
|
+
/>
|
|
58
|
+
)
|
|
59
|
+
})}
|
|
60
|
+
</FormSheet.Root>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const useStyles = () => {
|
|
65
|
+
return StyleSheet.create({
|
|
66
|
+
content: {
|
|
67
|
+
paddingTop: 20,
|
|
68
|
+
},
|
|
69
|
+
row: {
|
|
70
|
+
borderBottomWidth: 0,
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
}
|
|
@@ -53,6 +53,7 @@ export type ConversationRouteProps = {
|
|
|
53
53
|
subtitle?: string
|
|
54
54
|
badge?: ConversationBadgeResource
|
|
55
55
|
deleted?: boolean
|
|
56
|
+
muted?: boolean
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
export type ConversationScreenProps = StaticScreenProps<ConversationRouteProps>
|
|
@@ -109,6 +110,8 @@ function ConversationScreenContent({ route }: ConversationScreenProps) {
|
|
|
109
110
|
const replyHeaderTitle = replyRootAuthorFirstName
|
|
110
111
|
? `Reply to ${replyRootAuthorFirstName}`
|
|
111
112
|
: 'Reply'
|
|
113
|
+
// Prefer the membership for optimistic updates.
|
|
114
|
+
const muted = conversation.conversationMembership?.muted ?? conversation.muted
|
|
112
115
|
|
|
113
116
|
const listRef = useRef<FlatList>(null)
|
|
114
117
|
const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false)
|
|
@@ -134,9 +137,10 @@ function ConversationScreenContent({ route }: ConversationScreenProps) {
|
|
|
134
137
|
title: title,
|
|
135
138
|
badge: badges?.[0],
|
|
136
139
|
deleted: conversation?.deleted,
|
|
140
|
+
muted,
|
|
137
141
|
})
|
|
138
142
|
}
|
|
139
|
-
}, [navigation, title, badges, conversation?.deleted, reply_root_id, replyHeaderTitle])
|
|
143
|
+
}, [navigation, title, badges, conversation?.deleted, reply_root_id, replyHeaderTitle, muted])
|
|
140
144
|
|
|
141
145
|
if (!conversation || conversation.deleted) {
|
|
142
146
|
return (
|
|
@@ -390,6 +394,7 @@ interface ConversationScreenTitleProps extends HeaderTitleProps {
|
|
|
390
394
|
conversation_id: number
|
|
391
395
|
badge?: ConversationBadgeResource
|
|
392
396
|
deleted?: boolean
|
|
397
|
+
muted?: boolean
|
|
393
398
|
}
|
|
394
399
|
|
|
395
400
|
export const ConversationScreenTitle = ({
|
|
@@ -398,6 +403,7 @@ export const ConversationScreenTitle = ({
|
|
|
398
403
|
children,
|
|
399
404
|
style,
|
|
400
405
|
deleted,
|
|
406
|
+
muted,
|
|
401
407
|
}: ConversationScreenTitleProps) => {
|
|
402
408
|
const styles = usePressableHeaderStyle()
|
|
403
409
|
const navigation = useNavigation()
|
|
@@ -416,9 +422,12 @@ export const ConversationScreenTitle = ({
|
|
|
416
422
|
}}
|
|
417
423
|
>
|
|
418
424
|
<View style={styles.titleWrapper}>
|
|
419
|
-
<
|
|
420
|
-
{
|
|
421
|
-
|
|
425
|
+
<View style={styles.titleTextContainer}>
|
|
426
|
+
<HeaderTitle maxFontSizeMultiplier={1} style={style}>
|
|
427
|
+
{children}
|
|
428
|
+
</HeaderTitle>
|
|
429
|
+
</View>
|
|
430
|
+
{muted && <Icon name="general.bellMuted" size={12} />}
|
|
422
431
|
{!deleted && <Icon name="general.downChevron" size={12} />}
|
|
423
432
|
</View>
|
|
424
433
|
<Badge
|
|
@@ -438,6 +447,7 @@ const usePressableHeaderStyle = () => {
|
|
|
438
447
|
container: {
|
|
439
448
|
alignItems: Platform.select({ android: 'flex-start', default: 'center' }),
|
|
440
449
|
marginRight: Platform.select({ ios: 20, default: 16 }),
|
|
450
|
+
flex: 1,
|
|
441
451
|
},
|
|
442
452
|
titleWrapper: {
|
|
443
453
|
alignItems: 'center',
|
|
@@ -445,6 +455,10 @@ const usePressableHeaderStyle = () => {
|
|
|
445
455
|
flexDirection: 'row',
|
|
446
456
|
flexShrink: 1,
|
|
447
457
|
},
|
|
458
|
+
titleTextContainer: {
|
|
459
|
+
flexShrink: 1,
|
|
460
|
+
minWidth: 0,
|
|
461
|
+
},
|
|
448
462
|
badge: {
|
|
449
463
|
alignSelf: Platform.select({ android: 'flex-start', default: 'center' }),
|
|
450
464
|
marginTop: 2,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { StyleSheet } from 'react-native'
|
|
4
|
+
import { PressableRow } from '../components'
|
|
5
|
+
import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'
|
|
6
|
+
import { useTheme } from '../hooks'
|
|
7
|
+
import { useGroup, useGroupMembershipUpdate } from './notification_settings/hooks/groups'
|
|
8
|
+
|
|
9
|
+
export const GroupNotificationLevelSelectScreenOptions = getFormSheetScreenOptions({
|
|
10
|
+
headerTitle: 'Notification level',
|
|
11
|
+
sheetAllowedDetents: [0.35],
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
export type GroupNotificationLevelSelectScreenProps = StaticScreenProps<{
|
|
15
|
+
groupId: number | string
|
|
16
|
+
}>
|
|
17
|
+
|
|
18
|
+
export function GroupNotificationLevelSelectScreen({
|
|
19
|
+
route,
|
|
20
|
+
}: GroupNotificationLevelSelectScreenProps) {
|
|
21
|
+
const { groupId } = route.params
|
|
22
|
+
const navigation = useNavigation()
|
|
23
|
+
const styles = useStyles()
|
|
24
|
+
const { colors } = useTheme()
|
|
25
|
+
const { data: group } = useGroup({ groupId })
|
|
26
|
+
const { mutate: updateNotificationLevel } = useGroupMembershipUpdate({ groupId })
|
|
27
|
+
|
|
28
|
+
const notificationLevelOptions = group.myGroupMembership?.notificationLevelOptions ?? []
|
|
29
|
+
|
|
30
|
+
const handleSelect = (value: string, isActive: boolean) => {
|
|
31
|
+
if (!isActive) {
|
|
32
|
+
updateNotificationLevel({ notificationLevel: value })
|
|
33
|
+
}
|
|
34
|
+
navigation.goBack()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<FormSheet.Root contentStyle={styles.content}>
|
|
39
|
+
{notificationLevelOptions.map(option => (
|
|
40
|
+
<PressableRow
|
|
41
|
+
key={option.value}
|
|
42
|
+
text={option.description}
|
|
43
|
+
isActive={option.enabled}
|
|
44
|
+
onPress={() => handleSelect(option.value, option.enabled)}
|
|
45
|
+
iconColor={colors.statusSuccessIcon}
|
|
46
|
+
style={styles.row}
|
|
47
|
+
/>
|
|
48
|
+
))}
|
|
49
|
+
</FormSheet.Root>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const useStyles = () => {
|
|
54
|
+
return StyleSheet.create({
|
|
55
|
+
content: {
|
|
56
|
+
paddingTop: 20,
|
|
57
|
+
},
|
|
58
|
+
row: {
|
|
59
|
+
borderBottomWidth: 0,
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { PlatformPressable } from '@react-navigation/elements'
|
|
1
2
|
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
|
3
|
+
import type { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
|
2
4
|
import React, { useEffect } from 'react'
|
|
3
|
-
import { StyleSheet, View } from 'react-native'
|
|
4
|
-
import { Heading,
|
|
5
|
+
import { Platform, StyleSheet, View } from 'react-native'
|
|
6
|
+
import { Heading, Icon, Text } from '../components'
|
|
5
7
|
import { useTheme } from '../hooks'
|
|
6
8
|
import { platformFontWeightBold } from '../utils/styles'
|
|
7
|
-
import { useGroup
|
|
9
|
+
import { useGroup } from './notification_settings/hooks/groups'
|
|
10
|
+
import type { GroupNotificationLevelSelectScreenProps } from './group_notification_level_select_screen'
|
|
11
|
+
|
|
12
|
+
type GroupNotificationSettingsStackParamList = {
|
|
13
|
+
GroupNotificationLevelSelect: GroupNotificationLevelSelectScreenProps['route']['params']
|
|
14
|
+
}
|
|
8
15
|
|
|
9
16
|
export type GroupNotificationSettingsScreenProps = StaticScreenProps<{
|
|
10
17
|
groupId: number | string
|
|
@@ -13,12 +20,12 @@ export type GroupNotificationSettingsScreenProps = StaticScreenProps<{
|
|
|
13
20
|
|
|
14
21
|
export function GroupNotificationSettingsScreen({ route }: GroupNotificationSettingsScreenProps) {
|
|
15
22
|
const { groupId, title } = route.params
|
|
16
|
-
const navigation =
|
|
23
|
+
const navigation =
|
|
24
|
+
useNavigation<NativeStackNavigationProp<GroupNotificationSettingsStackParamList>>()
|
|
17
25
|
const styles = useStyles()
|
|
18
26
|
const { data: group } = useGroup({ groupId })
|
|
19
|
-
const { mutate: updateNotificationLevel } = useGroupMembershipUpdate({ groupId })
|
|
20
27
|
|
|
21
|
-
const
|
|
28
|
+
const notificationLevelDescription = group.myGroupMembership?.notificationLevelDescription
|
|
22
29
|
|
|
23
30
|
useEffect(() => {
|
|
24
31
|
if (!group.name || title === group.name) return
|
|
@@ -26,9 +33,8 @@ export function GroupNotificationSettingsScreen({ route }: GroupNotificationSett
|
|
|
26
33
|
navigation.setOptions({ title: group.name })
|
|
27
34
|
}, [group.name, title, navigation])
|
|
28
35
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
updateNotificationLevel(notificationLevel)
|
|
36
|
+
const handleOpenSelector = () => {
|
|
37
|
+
navigation.navigate('GroupNotificationLevelSelect', { groupId })
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
return (
|
|
@@ -44,10 +50,30 @@ export function GroupNotificationSettingsScreen({ route }: GroupNotificationSett
|
|
|
44
50
|
</Text>
|
|
45
51
|
</View>
|
|
46
52
|
</View>
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
<PlatformPressable
|
|
54
|
+
style={styles.settingRowPressable}
|
|
55
|
+
onPress={handleOpenSelector}
|
|
56
|
+
accessibilityRole="button"
|
|
57
|
+
accessibilityLabel="Notify me for"
|
|
58
|
+
accessibilityHint={`Currently set to ${notificationLevelDescription}. Tap to change.`}
|
|
59
|
+
>
|
|
60
|
+
<View style={styles.settingRowInner}>
|
|
61
|
+
<View style={styles.settingRowText}>
|
|
62
|
+
<Text>Notify me for</Text>
|
|
63
|
+
{Boolean(notificationLevelDescription) && (
|
|
64
|
+
<Text variant="tertiary">{notificationLevelDescription}</Text>
|
|
65
|
+
)}
|
|
66
|
+
</View>
|
|
67
|
+
{Platform.OS === 'ios' && (
|
|
68
|
+
<Icon
|
|
69
|
+
name="general.rightChevron"
|
|
70
|
+
size={16}
|
|
71
|
+
style={styles.chevron}
|
|
72
|
+
accessibilityElementsHidden
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
75
|
+
</View>
|
|
76
|
+
</PlatformPressable>
|
|
51
77
|
</View>
|
|
52
78
|
)
|
|
53
79
|
}
|
|
@@ -66,7 +92,7 @@ const useStyles = () => {
|
|
|
66
92
|
},
|
|
67
93
|
sectionInner: {
|
|
68
94
|
paddingRight: 16,
|
|
69
|
-
paddingTop:
|
|
95
|
+
paddingTop: 24,
|
|
70
96
|
paddingBottom: 12,
|
|
71
97
|
borderBottomWidth: 1,
|
|
72
98
|
borderBottomColor: colors.borderColorDefaultBase,
|
|
@@ -80,13 +106,22 @@ const useStyles = () => {
|
|
|
80
106
|
groupNameBold: {
|
|
81
107
|
fontWeight: platformFontWeightBold,
|
|
82
108
|
},
|
|
83
|
-
|
|
109
|
+
settingRowPressable: {
|
|
110
|
+
paddingLeft: 16,
|
|
111
|
+
},
|
|
112
|
+
settingRowInner: {
|
|
84
113
|
flexDirection: 'row',
|
|
85
|
-
justifyContent: 'space-between',
|
|
86
114
|
alignItems: 'center',
|
|
87
|
-
|
|
115
|
+
justifyContent: 'space-between',
|
|
116
|
+
paddingRight: 16,
|
|
88
117
|
paddingVertical: 12,
|
|
89
|
-
|
|
118
|
+
},
|
|
119
|
+
settingRowText: {
|
|
120
|
+
flex: 1,
|
|
121
|
+
gap: 2,
|
|
122
|
+
},
|
|
123
|
+
chevron: {
|
|
124
|
+
color: colors.iconColorDefaultDisabled,
|
|
90
125
|
},
|
|
91
126
|
})
|
|
92
127
|
}
|