@planningcenter/chat-react-native 3.2.0-rc.0 → 3.2.0-rc.2
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/conversation/message_form.js.map +1 -1
- package/build/components/conversation/message_reaction.d.ts +2 -2
- package/build/components/conversations/action_toggle_button.d.ts +21 -0
- package/build/components/conversations/action_toggle_button.d.ts.map +1 -0
- package/build/components/conversations/action_toggle_button.js +47 -0
- package/build/components/conversations/action_toggle_button.js.map +1 -0
- package/build/components/conversations/conversation_actions.d.ts +10 -0
- package/build/components/conversations/conversation_actions.d.ts.map +1 -0
- package/build/components/conversations/conversation_actions.js +70 -0
- package/build/components/conversations/conversation_actions.js.map +1 -0
- package/build/components/conversations/conversation_preview.d.ts +2 -1
- package/build/components/conversations/conversation_preview.d.ts.map +1 -1
- package/build/components/conversations/conversation_preview.js +27 -9
- package/build/components/conversations/conversation_preview.js.map +1 -1
- package/build/components/conversations/conversations.d.ts +5 -3
- package/build/components/conversations/conversations.d.ts.map +1 -1
- package/build/components/conversations/conversations.js +11 -7
- package/build/components/conversations/conversations.js.map +1 -1
- package/build/components/conversations/mute_indicator.d.ts +5 -0
- package/build/components/conversations/mute_indicator.d.ts.map +1 -0
- package/build/components/conversations/mute_indicator.js +19 -0
- package/build/components/conversations/mute_indicator.js.map +1 -0
- package/build/components/conversations/unread_count_badge.d.ts +2 -1
- package/build/components/conversations/unread_count_badge.d.ts.map +1 -1
- package/build/components/conversations/unread_count_badge.js +9 -1
- package/build/components/conversations/unread_count_badge.js.map +1 -1
- package/build/components/display/badge.d.ts +5 -4
- package/build/components/display/badge.d.ts.map +1 -1
- package/build/components/display/badge.js +5 -2
- package/build/components/display/badge.js.map +1 -1
- package/build/components/display/button.d.ts +3 -2
- package/build/components/display/button.d.ts.map +1 -1
- package/build/components/display/button.js.map +1 -1
- package/build/components/display/icon.d.ts +14 -1
- package/build/components/display/icon.d.ts.map +1 -1
- package/build/components/display/icon.js +9 -0
- package/build/components/display/icon.js.map +1 -1
- package/build/components/display/icon_button.d.ts +2 -2
- package/build/components/display/icon_button.d.ts.map +1 -1
- package/build/components/display/icon_button.js.map +1 -1
- package/build/components/display/index.d.ts +1 -0
- package/build/components/display/index.d.ts.map +1 -1
- package/build/components/display/index.js +1 -0
- package/build/components/display/index.js.map +1 -1
- package/build/components/display/text.js.map +1 -1
- package/build/components/display/toggle_button.d.ts +43 -0
- package/build/components/display/toggle_button.d.ts.map +1 -0
- package/build/components/display/toggle_button.js +67 -0
- package/build/components/display/toggle_button.js.map +1 -0
- package/build/components/display/utils/button_colors.d.ts +3 -3
- package/build/components/display/utils/button_colors.d.ts.map +1 -1
- package/build/components/display/utils/button_colors.js +1 -1
- package/build/components/display/utils/button_colors.js.map +1 -1
- package/build/components/page/error_boundary.d.ts +1 -1
- package/build/components/primitive/avatar_primitive.d.ts.map +1 -1
- package/build/components/primitive/avatar_primitive.js +3 -2
- package/build/components/primitive/avatar_primitive.js.map +1 -1
- package/build/components/primitive/banner_primitive.d.ts +2 -1
- package/build/components/primitive/banner_primitive.d.ts.map +1 -1
- package/build/components/primitive/banner_primitive.js.map +1 -1
- package/build/contexts/api_provider.js.map +1 -1
- package/build/contexts/swipeable_active_conversation.d.ts +11 -0
- package/build/contexts/swipeable_active_conversation.d.ts.map +1 -0
- package/build/contexts/swipeable_active_conversation.js +16 -0
- package/build/contexts/swipeable_active_conversation.js.map +1 -0
- package/build/hooks/use_conversation.d.ts +1 -1
- package/build/hooks/use_conversation.d.ts.map +1 -1
- package/build/hooks/use_conversation.js +1 -1
- package/build/hooks/use_conversation.js.map +1 -1
- package/build/hooks/use_create_android_ripple_color.d.ts +1 -1
- package/build/hooks/use_create_android_ripple_color.d.ts.map +1 -1
- package/build/hooks/use_jolt.js +1 -1
- package/build/hooks/use_jolt.js.map +1 -1
- package/build/navigation/index.d.ts +9 -1
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +13 -1
- package/build/navigation/index.js.map +1 -1
- package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
- package/build/screens/conversation_filters/components/rows.d.ts +2 -1
- package/build/screens/conversation_filters/components/rows.d.ts.map +1 -1
- package/build/screens/conversation_filters/components/rows.js +19 -14
- package/build/screens/conversation_filters/components/rows.js.map +1 -1
- package/build/screens/conversations/components/chat_group_badge.d.ts +3 -0
- package/build/screens/conversations/components/chat_group_badge.d.ts.map +1 -0
- package/build/screens/conversations/components/chat_group_badge.js +40 -0
- package/build/screens/conversations/components/chat_group_badge.js.map +1 -0
- package/build/screens/conversations/components/list_header_component.d.ts +3 -0
- package/build/screens/conversations/components/list_header_component.d.ts.map +1 -0
- package/build/screens/conversations/components/list_header_component.js +88 -0
- package/build/screens/conversations/components/list_header_component.js.map +1 -0
- package/build/screens/{conversations_screen.d.ts → conversations/conversations_screen.d.ts} +1 -1
- package/build/screens/conversations/conversations_screen.d.ts.map +1 -0
- package/build/screens/conversations/conversations_screen.js +35 -0
- package/build/screens/conversations/conversations_screen.js.map +1 -0
- package/build/screens/create/conversation_create_screen.d.ts.map +1 -1
- package/build/screens/create/conversation_create_screen.js +0 -1
- package/build/screens/create/conversation_create_screen.js.map +1 -1
- package/build/screens/design_system_screen.d.ts.map +1 -1
- package/build/screens/design_system_screen.js +10 -1
- package/build/screens/design_system_screen.js.map +1 -1
- package/build/screens/message_actions_screen.js +1 -1
- package/build/screens/message_actions_screen.js.map +1 -1
- package/build/utils/client/client.d.ts +2 -2
- package/build/utils/client/client.d.ts.map +1 -1
- package/build/utils/client/client.js +12 -4
- package/build/utils/client/client.js.map +1 -1
- package/build/utils/client/request_helpers.d.ts +15 -8
- package/build/utils/client/request_helpers.d.ts.map +1 -1
- package/build/utils/client/request_helpers.js +2 -1
- package/build/utils/client/request_helpers.js.map +1 -1
- package/build/utils/client/transform_request_data.d.ts +11 -6
- package/build/utils/client/transform_request_data.d.ts.map +1 -1
- package/build/utils/client/transform_request_data.js +1 -1
- package/build/utils/client/transform_request_data.js.map +1 -1
- package/build/utils/client/transform_response.d.ts +1 -1
- package/build/utils/client/transform_response.d.ts.map +1 -1
- package/build/utils/client/transform_response.js +2 -0
- package/build/utils/client/transform_response.js.map +1 -1
- package/build/utils/client/utils.d.ts +3 -3
- package/build/utils/client/utils.d.ts.map +1 -1
- package/build/utils/client/utils.js +6 -6
- package/build/utils/client/utils.js.map +1 -1
- package/build/utils/date.d.ts.map +1 -1
- package/build/utils/date.js +1 -0
- package/build/utils/date.js.map +1 -1
- package/build/utils/deepCamelCaseKeys.d.ts.map +1 -1
- package/build/utils/deepCamelCaseKeys.js +3 -1
- package/build/utils/deepCamelCaseKeys.js.map +1 -1
- package/build/utils/parse_simple_markdown.d.ts +1 -1
- package/build/utils/parse_simple_markdown.d.ts.map +1 -1
- package/build/utils/parse_simple_markdown.js +2 -1
- package/build/utils/parse_simple_markdown.js.map +1 -1
- package/build/utils/space.js.map +1 -1
- package/build/utils/uri.d.ts +2 -2
- package/build/utils/uri.d.ts.map +1 -1
- package/build/utils/uri.js +2 -2
- package/build/utils/uri.js.map +1 -1
- package/build/vendor/tapestry/alias_tokens_color_map.d.ts +8 -0
- package/build/vendor/tapestry/alias_tokens_color_map.d.ts.map +1 -1
- package/build/vendor/tapestry/alias_tokens_color_map.js +8 -0
- package/build/vendor/tapestry/alias_tokens_color_map.js.map +1 -1
- package/build/vendor/tapestry/tokens.d.ts +2 -0
- package/build/vendor/tapestry/tokens.d.ts.map +1 -1
- package/build/vendor/tapestry/tokens.js +2 -0
- package/build/vendor/tapestry/tokens.js.map +1 -1
- package/package.json +8 -6
- package/src/components/conversation/message_form.tsx +1 -1
- package/src/components/conversations/action_toggle_button.tsx +83 -0
- package/src/components/conversations/conversation_actions.tsx +119 -0
- package/src/components/conversations/conversation_preview.tsx +46 -16
- package/src/components/conversations/conversations.tsx +38 -30
- package/src/components/conversations/mute_indicator.tsx +21 -0
- package/src/components/conversations/unread_count_badge.tsx +8 -1
- package/src/components/display/badge.tsx +12 -8
- package/src/components/display/button.tsx +3 -3
- package/src/components/display/icon.tsx +16 -3
- package/src/components/display/icon_button.tsx +2 -2
- package/src/components/display/index.ts +1 -0
- package/src/components/display/text.tsx +1 -1
- package/src/components/display/toggle_button.tsx +157 -0
- package/src/components/display/utils/button_colors.ts +8 -3
- package/src/components/primitive/avatar_primitive.tsx +5 -3
- package/src/components/primitive/banner_primitive.tsx +2 -2
- package/src/contexts/api_provider.tsx +1 -1
- package/src/contexts/swipeable_active_conversation.tsx +27 -0
- package/src/hooks/use_conversation.ts +5 -5
- package/src/hooks/use_jolt.ts +2 -2
- package/src/navigation/index.tsx +19 -1
- package/src/screens/conversation_filters/components/conversation_filters.tsx +1 -1
- package/src/screens/conversation_filters/components/rows.tsx +44 -14
- package/src/screens/conversations/components/chat_group_badge.tsx +47 -0
- package/src/screens/conversations/components/list_header_component.tsx +125 -0
- package/src/screens/conversations/conversations_screen.tsx +56 -0
- package/src/screens/create/conversation_create_screen.tsx +7 -4
- package/src/screens/design_system_screen.tsx +29 -0
- package/src/screens/message_actions_screen.tsx +2 -2
- package/src/utils/client/client.ts +15 -7
- package/src/utils/client/request_helpers.ts +15 -6
- package/src/utils/client/transform_request_data.ts +13 -4
- package/src/utils/client/transform_response.ts +3 -0
- package/src/utils/client/types.d.ts +2 -1
- package/src/utils/client/utils.ts +13 -12
- package/src/utils/date.ts +1 -0
- package/src/utils/deepCamelCaseKeys.ts +3 -2
- package/src/utils/parse_simple_markdown.ts +3 -1
- package/src/utils/space.ts +1 -1
- package/src/utils/uri.ts +2 -2
- package/src/vendor/tapestry/alias_tokens_color_map.ts +12 -0
- package/src/vendor/tapestry/tokens.ts +2 -0
- package/build/screens/conversations_screen.d.ts.map +0 -1
- package/build/screens/conversations_screen.js +0 -144
- package/build/screens/conversations_screen.js.map +0 -1
- package/src/screens/conversations_screen.tsx +0 -222
|
@@ -4,14 +4,24 @@ import type { ColorValue, StyleProp, ViewStyle } from 'react-native'
|
|
|
4
4
|
import { SvgXml } from 'react-native-svg'
|
|
5
5
|
import type { XmlProps } from 'react-native-svg'
|
|
6
6
|
import { useFontScale, useTheme } from '../../hooks'
|
|
7
|
+
|
|
8
|
+
// @ts-ignore
|
|
7
9
|
import * as api from '@planningcenter/icons/paths/api'
|
|
10
|
+
// @ts-ignore
|
|
8
11
|
import * as brand from '@planningcenter/icons/paths/brand'
|
|
12
|
+
// @ts-ignore
|
|
9
13
|
import * as calendar from '@planningcenter/icons/paths/calendar'
|
|
14
|
+
// @ts-ignore
|
|
10
15
|
import * as churchCenter from '@planningcenter/icons/paths/church-center'
|
|
16
|
+
// @ts-ignore
|
|
11
17
|
import * as general from '@planningcenter/icons/paths/general'
|
|
18
|
+
// @ts-ignore
|
|
12
19
|
import * as groups from '@planningcenter/icons/paths/groups'
|
|
20
|
+
// @ts-ignore
|
|
13
21
|
import * as logomark from '@planningcenter/icons/paths/logomark'
|
|
22
|
+
// @ts-ignore
|
|
14
23
|
import * as people from '@planningcenter/icons/paths/people'
|
|
24
|
+
// @ts-ignore
|
|
15
25
|
import * as services from '@planningcenter/icons/paths/services'
|
|
16
26
|
|
|
17
27
|
// =================================
|
|
@@ -37,6 +47,9 @@ type IconStyle = ViewStyle & {
|
|
|
37
47
|
color?: string
|
|
38
48
|
}
|
|
39
49
|
|
|
50
|
+
export type IconSetName = keyof typeof ICONS
|
|
51
|
+
export type IconString = `${IconSetName}.${(typeof ICONS)[IconSetName]}`
|
|
52
|
+
|
|
40
53
|
// =================================
|
|
41
54
|
// ====== Component ================
|
|
42
55
|
// =================================
|
|
@@ -46,7 +59,7 @@ export interface IconProps extends Omit<XmlProps, 'xml' | 'fontSize'> {
|
|
|
46
59
|
* Made up of the set.iconName.
|
|
47
60
|
* Example: "general.textMessage"
|
|
48
61
|
*/
|
|
49
|
-
name:
|
|
62
|
+
name: IconString
|
|
50
63
|
/**
|
|
51
64
|
* This sets a static size for the icon.
|
|
52
65
|
* Providing a fontSize style will allow the icon to scale with the device's text a11y size.
|
|
@@ -112,10 +125,10 @@ const useGetIconSize = (size?: number, style?: IconStyle, maxFontSizeMultiplier?
|
|
|
112
125
|
return size || FALLBACK_SIZE
|
|
113
126
|
}
|
|
114
127
|
|
|
115
|
-
const getIconPath = (name:
|
|
128
|
+
const getIconPath = (name: IconString): string => {
|
|
116
129
|
const [setName, iconName] = name.split('.')
|
|
117
130
|
|
|
118
|
-
return ICONS[setName]?.[iconName]
|
|
131
|
+
return ICONS[setName as IconSetName]?.[iconName]
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
// =================================
|
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
|
2
2
|
import { Pressable, StyleSheet } from 'react-native'
|
|
3
3
|
import type { PressableProps, ViewStyle } from 'react-native'
|
|
4
4
|
import { Icon } from './icon'
|
|
5
|
-
import type { IconProps } from './icon'
|
|
5
|
+
import type { IconProps, IconString } from './icon'
|
|
6
6
|
import { useTheme, useFontScale, useCreateAndroidRippleColor } from '../../hooks'
|
|
7
7
|
import { platformPressedOpacityStyle } from '../../utils'
|
|
8
8
|
import { Spinner } from './spinner'
|
|
@@ -67,7 +67,7 @@ interface IconButtonProps extends PressableProps {
|
|
|
67
67
|
/**
|
|
68
68
|
* Generates an icon from `@planningcenter/icons`
|
|
69
69
|
*/
|
|
70
|
-
name:
|
|
70
|
+
name: IconString
|
|
71
71
|
/**
|
|
72
72
|
* Changes the overall size of the button and its contents
|
|
73
73
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useTheme } from '../../hooks'
|
|
2
2
|
import React from 'react'
|
|
3
|
-
import {
|
|
3
|
+
import { StyleSheet, Text as ReactNativeText } from 'react-native'
|
|
4
4
|
import type { TextStyle, TextProps as ReactNativeTextProps } from 'react-native'
|
|
5
5
|
import { tokens } from '../../vendor/tapestry/tokens'
|
|
6
6
|
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import React, { useMemo } from 'react'
|
|
2
|
+
import { Pressable, StyleSheet } from 'react-native'
|
|
3
|
+
import type { PressableProps } from 'react-native'
|
|
4
|
+
import { Text } from './text'
|
|
5
|
+
import { useTheme, useFontScale, useCreateAndroidRippleColor } from '../../hooks'
|
|
6
|
+
import { platformFontWeightBold, platformPressedOpacityStyle } from '../../utils'
|
|
7
|
+
import colorFunction from 'color'
|
|
8
|
+
import { Icon, IconString } from './icon'
|
|
9
|
+
import { tokens } from '../../vendor/tapestry/tokens'
|
|
10
|
+
|
|
11
|
+
// =================================
|
|
12
|
+
// ====== Component ================
|
|
13
|
+
// =================================
|
|
14
|
+
|
|
15
|
+
export interface ToggleButtonProps extends PressableProps {
|
|
16
|
+
/**
|
|
17
|
+
* Pressable container styles
|
|
18
|
+
*/
|
|
19
|
+
active: boolean
|
|
20
|
+
/**
|
|
21
|
+
* Specifies whether fonts should be scaled down automatically to fit given style constraints.
|
|
22
|
+
*/
|
|
23
|
+
adjustsFontSizeToFit?: boolean
|
|
24
|
+
/**
|
|
25
|
+
* Specifies whether fonts should scale to respect the device's text size accessibility settings. The default is true.
|
|
26
|
+
*/
|
|
27
|
+
allowFontScaling?: boolean
|
|
28
|
+
/**
|
|
29
|
+
* Generates an icon to the left of the button text
|
|
30
|
+
*/
|
|
31
|
+
iconNameLeft?: IconString
|
|
32
|
+
/**
|
|
33
|
+
* Generates an icon to the right of the button text
|
|
34
|
+
*/
|
|
35
|
+
iconNameRight?: IconString
|
|
36
|
+
/**
|
|
37
|
+
* Specifies the maximum size a font can reach when allowFontScaling is enabled.
|
|
38
|
+
*/
|
|
39
|
+
maxFontSizeMultiplier?: number
|
|
40
|
+
/**
|
|
41
|
+
* Specifies smallest possible scale a font can reach when adjustsFontSizeToFit is enabled. (values 0.01-1.0).
|
|
42
|
+
*/
|
|
43
|
+
minimumFontScale?: number
|
|
44
|
+
/**
|
|
45
|
+
* Renders as text within the button
|
|
46
|
+
*/
|
|
47
|
+
title: string
|
|
48
|
+
/**
|
|
49
|
+
* Pressable container styles
|
|
50
|
+
*/
|
|
51
|
+
style?: PressableProps['style']
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function ToggleButton({
|
|
55
|
+
active,
|
|
56
|
+
adjustsFontSizeToFit = false,
|
|
57
|
+
allowFontScaling = true,
|
|
58
|
+
iconNameLeft,
|
|
59
|
+
iconNameRight,
|
|
60
|
+
maxFontSizeMultiplier,
|
|
61
|
+
minimumFontScale,
|
|
62
|
+
title,
|
|
63
|
+
style,
|
|
64
|
+
...props
|
|
65
|
+
}: ToggleButtonProps) {
|
|
66
|
+
const styles = useStyles({ active, maxFontSizeMultiplier })
|
|
67
|
+
const { colors } = useTheme()
|
|
68
|
+
const overrideStyles = StyleSheet.flatten(style) // Ensures the pressed styles still get applied
|
|
69
|
+
|
|
70
|
+
const baseRippleColor = active ? colors.interaction : colors.fillColorNeutral050Base
|
|
71
|
+
const androidRippleColor = useCreateAndroidRippleColor({ color: baseRippleColor })
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<Pressable
|
|
75
|
+
style={({ pressed }) => ({
|
|
76
|
+
...styles.pressable,
|
|
77
|
+
...(pressed ? platformPressedOpacityStyle : null),
|
|
78
|
+
...overrideStyles,
|
|
79
|
+
})}
|
|
80
|
+
accessibilityRole="togglebutton"
|
|
81
|
+
accessibilityState={{ checked: active }}
|
|
82
|
+
android_ripple={{ color: androidRippleColor, borderless: false, foreground: true }}
|
|
83
|
+
{...props}
|
|
84
|
+
>
|
|
85
|
+
{iconNameLeft && (
|
|
86
|
+
<Icon
|
|
87
|
+
name={iconNameLeft}
|
|
88
|
+
style={styles.icon}
|
|
89
|
+
maxFontSizeMultiplier={maxFontSizeMultiplier}
|
|
90
|
+
/>
|
|
91
|
+
)}
|
|
92
|
+
<Text
|
|
93
|
+
allowFontScaling={allowFontScaling}
|
|
94
|
+
minimumFontScale={minimumFontScale}
|
|
95
|
+
maxFontSizeMultiplier={maxFontSizeMultiplier}
|
|
96
|
+
adjustsFontSizeToFit={adjustsFontSizeToFit}
|
|
97
|
+
numberOfLines={1}
|
|
98
|
+
style={styles.text}
|
|
99
|
+
variant="tertiary"
|
|
100
|
+
>
|
|
101
|
+
{title}
|
|
102
|
+
</Text>
|
|
103
|
+
{iconNameRight && (
|
|
104
|
+
<Icon
|
|
105
|
+
name={iconNameRight}
|
|
106
|
+
style={styles.icon}
|
|
107
|
+
maxFontSizeMultiplier={maxFontSizeMultiplier}
|
|
108
|
+
/>
|
|
109
|
+
)}
|
|
110
|
+
</Pressable>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// =================================
|
|
115
|
+
// ====== Styles ===================
|
|
116
|
+
// =================================
|
|
117
|
+
|
|
118
|
+
const useStyles = ({ active, maxFontSizeMultiplier }: Partial<ToggleButtonProps>) => {
|
|
119
|
+
const { colors, button } = useTheme()
|
|
120
|
+
const fontScale = useFontScale({ maxFontSizeMultiplier })
|
|
121
|
+
|
|
122
|
+
const activeBackgroundColor = useMemo(() => {
|
|
123
|
+
return colorFunction(colors.interaction)
|
|
124
|
+
.hsl()
|
|
125
|
+
.lightness(colors.name === 'dark' ? 12 : 92)
|
|
126
|
+
.string()
|
|
127
|
+
}, [colors.interaction, colors.name])
|
|
128
|
+
|
|
129
|
+
const color = active ? colors.interaction : colors.textColorDefaultSecondary
|
|
130
|
+
|
|
131
|
+
return StyleSheet.create({
|
|
132
|
+
pressable: {
|
|
133
|
+
borderRadius: button.borderRadius * fontScale,
|
|
134
|
+
borderWidth: 1,
|
|
135
|
+
borderColor: active ? colors.interaction : colors.borderColorDefaultBase,
|
|
136
|
+
backgroundColor: active ? activeBackgroundColor : 'transparent',
|
|
137
|
+
paddingHorizontal: 16 * fontScale,
|
|
138
|
+
flexDirection: 'row',
|
|
139
|
+
alignItems: 'center',
|
|
140
|
+
justifyContent: 'center',
|
|
141
|
+
height: 32 * fontScale,
|
|
142
|
+
gap: 6 * fontScale,
|
|
143
|
+
overflow: 'hidden',
|
|
144
|
+
},
|
|
145
|
+
text: {
|
|
146
|
+
textAlign: 'center',
|
|
147
|
+
textAlignVertical: 'center',
|
|
148
|
+
includeFontPadding: false,
|
|
149
|
+
fontWeight: platformFontWeightBold,
|
|
150
|
+
color,
|
|
151
|
+
},
|
|
152
|
+
icon: {
|
|
153
|
+
fontSize: tokens.fontSizeSm * fontScale,
|
|
154
|
+
color,
|
|
155
|
+
},
|
|
156
|
+
})
|
|
157
|
+
}
|
|
@@ -89,12 +89,17 @@ function useGradientColorMap(): GradientColorMap {
|
|
|
89
89
|
// ====== Functions ================
|
|
90
90
|
// =================================
|
|
91
91
|
|
|
92
|
-
interface GetColorKeyArgs {
|
|
92
|
+
interface GetColorKeyArgs<T> {
|
|
93
93
|
disabled: boolean | null
|
|
94
94
|
loading?: boolean
|
|
95
|
-
appearance:
|
|
95
|
+
appearance: T
|
|
96
96
|
}
|
|
97
|
-
|
|
97
|
+
|
|
98
|
+
function getColorKey<T extends ButtonAppearanceUnion | IconButtonAppearanceUnion>({
|
|
99
|
+
disabled,
|
|
100
|
+
loading,
|
|
101
|
+
appearance,
|
|
102
|
+
}: GetColorKeyArgs<T>) {
|
|
98
103
|
if (disabled || loading) return 'disabled'
|
|
99
104
|
return appearance
|
|
100
105
|
}
|
|
@@ -168,10 +168,11 @@ interface AvatarGroupProps {
|
|
|
168
168
|
sourceUris: string[]
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
type AvatarIndex = 0 | 1 | 2 | 3
|
|
171
172
|
function AvatarGroup({ sourceUris }: AvatarGroupProps) {
|
|
172
173
|
const styles = useStyles()
|
|
173
174
|
const { setAllImagesLoaded } = useAvatarContext()
|
|
174
|
-
const [loadingStatus, setLoadingStatus] = useState({
|
|
175
|
+
const [loadingStatus, setLoadingStatus] = useState<Record<AvatarIndex, boolean>>({
|
|
175
176
|
0: false,
|
|
176
177
|
1: false,
|
|
177
178
|
2: false,
|
|
@@ -180,7 +181,7 @@ function AvatarGroup({ sourceUris }: AvatarGroupProps) {
|
|
|
180
181
|
const displayUris = sourceUris.slice(0, 4)
|
|
181
182
|
const hasDisplayUris = displayUris.length > 0
|
|
182
183
|
|
|
183
|
-
const handleImageLoaded = index => {
|
|
184
|
+
const handleImageLoaded = (index: AvatarIndex) => {
|
|
184
185
|
setLoadingStatus(prev => ({
|
|
185
186
|
...prev,
|
|
186
187
|
[index]: true,
|
|
@@ -189,7 +190,8 @@ function AvatarGroup({ sourceUris }: AvatarGroupProps) {
|
|
|
189
190
|
|
|
190
191
|
useEffect(() => {
|
|
191
192
|
const allImagesLoaded =
|
|
192
|
-
hasDisplayUris &&
|
|
193
|
+
hasDisplayUris &&
|
|
194
|
+
displayUris.every((_, index) => loadingStatus[index as AvatarIndex] === true)
|
|
193
195
|
|
|
194
196
|
setAllImagesLoaded(allImagesLoaded)
|
|
195
197
|
}, [displayUris, hasDisplayUris, loadingStatus, setAllImagesLoaded])
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from '../../utils'
|
|
13
13
|
import { tokens } from '../../vendor/tapestry/tokens'
|
|
14
14
|
import { useCreateAndroidRippleColor, useFontScale } from '../../hooks'
|
|
15
|
-
import { Icon } from '../display/icon'
|
|
15
|
+
import { Icon, IconString } from '../display/icon'
|
|
16
16
|
import { Heading } from '../display/heading'
|
|
17
17
|
import { Text } from '../display/text'
|
|
18
18
|
import { TextInlineButton } from '../display/text_inline_button'
|
|
@@ -161,7 +161,7 @@ BannerContent.displayName = 'Banner.Content'
|
|
|
161
161
|
// ========================================
|
|
162
162
|
|
|
163
163
|
interface BannerStatusIconProps {
|
|
164
|
-
iconName?:
|
|
164
|
+
iconName?: IconString
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
function BannerStatusIcon({ iconName }: BannerStatusIconProps) {
|
|
@@ -48,7 +48,7 @@ function useSessionChanged(value: Pick<ChatContextValue, 'token' | 'env'>): bool
|
|
|
48
48
|
return Boolean(prevToken && newToken !== prevToken) || Boolean(prevEnv && newEnv !== prevEnv)
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function usePrevious<T>(value) {
|
|
51
|
+
function usePrevious<T>(value: T): T {
|
|
52
52
|
const ref = useRef<T>(value)
|
|
53
53
|
|
|
54
54
|
useEffect(() => {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React, { createContext, useContext, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
type ConversationActionsValue = {
|
|
4
|
+
activeConversationId?: number
|
|
5
|
+
setActiveConversationId: (_id: number) => void
|
|
6
|
+
}
|
|
7
|
+
const ConversationActionsContext = createContext<ConversationActionsValue>({
|
|
8
|
+
activeConversationId: undefined,
|
|
9
|
+
setActiveConversationId: () => {},
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
export const ConversationActionsProvider = ({ children }: { children: React.ReactNode }) => {
|
|
13
|
+
const [activeConversationId, setActiveConversationId] = useState<number | undefined>()
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<ConversationActionsContext.Provider
|
|
17
|
+
value={{
|
|
18
|
+
activeConversationId,
|
|
19
|
+
setActiveConversationId,
|
|
20
|
+
}}
|
|
21
|
+
>
|
|
22
|
+
{children}
|
|
23
|
+
</ConversationActionsContext.Provider>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const useConversationActionsContext = () => useContext(ConversationActionsContext)
|
|
@@ -34,7 +34,7 @@ export const getConversationRequestArgs = ({ conversation_id }: { conversation_i
|
|
|
34
34
|
},
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
-
export const useConversation = ({ conversation_id }) => {
|
|
37
|
+
export const useConversation = ({ conversation_id }: { conversation_id: number }) => {
|
|
38
38
|
return useSuspenseGet<ConversationResource>(getConversationRequestArgs({ conversation_id }))
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -60,7 +60,7 @@ export const useConversationMute = ({ conversation_id }: { conversation_id: numb
|
|
|
60
60
|
mutationFn: async (muted: boolean) => {
|
|
61
61
|
const action = muted ? 'mute' : 'unmute'
|
|
62
62
|
|
|
63
|
-
return apiClient.chat.post({
|
|
63
|
+
return apiClient.chat.post<ApiResource<ConversationResource>>({
|
|
64
64
|
url: `/me/conversations/${conversation_id}/${action}`,
|
|
65
65
|
data: { data: { type: '', attributes: {} }, fields: { Conversation: 'muted' } },
|
|
66
66
|
})
|
|
@@ -104,12 +104,12 @@ export const useConversationUpdate = ({ conversation_id }: { conversation_id: nu
|
|
|
104
104
|
mutationKey: ['mutateConversation'],
|
|
105
105
|
mutationFn: async (update: Partial<ConversationResource>) => {
|
|
106
106
|
const postArgs = transformGetToPost(requestArgs).data
|
|
107
|
-
return apiClient.chat.patch({
|
|
107
|
+
return apiClient.chat.patch<ApiResource<ConversationResource>>({
|
|
108
108
|
url: `/me/conversations/${conversation_id}/`,
|
|
109
109
|
data: { data: { type: '', attributes: update }, ...postArgs },
|
|
110
110
|
})
|
|
111
111
|
},
|
|
112
|
-
onSuccess:
|
|
112
|
+
onSuccess: response => {
|
|
113
113
|
queryClient.setQueryData<ApiResource<ConversationResource>>(queryKey, () => response)
|
|
114
114
|
},
|
|
115
115
|
})
|
|
@@ -153,7 +153,7 @@ export const useConversationDisableReplies = ({ conversation_id }: { conversatio
|
|
|
153
153
|
},
|
|
154
154
|
mutationKey: ['disableRepliesConversation'],
|
|
155
155
|
mutationFn: async (repliesDisabled: boolean) => {
|
|
156
|
-
return apiClient.chat.patch({
|
|
156
|
+
return apiClient.chat.patch<ApiResource<ConversationResource>>({
|
|
157
157
|
url: `/me/conversations/${conversation_id}`,
|
|
158
158
|
data: {
|
|
159
159
|
data: {
|
package/src/hooks/use_jolt.ts
CHANGED
|
@@ -38,7 +38,7 @@ export const useJoltClient = (): JoltClient | undefined => {
|
|
|
38
38
|
|
|
39
39
|
const fetchSubscribeTokenFn: FetchSubscribeToken = (channel: string, connectionId: string) => {
|
|
40
40
|
return apiClient.chat
|
|
41
|
-
.post({
|
|
41
|
+
.post<ApiResource<JoltResponse>>({
|
|
42
42
|
url: '/me/jolt_subscribe',
|
|
43
43
|
data: {
|
|
44
44
|
data: {
|
|
@@ -47,7 +47,7 @@ export const useJoltClient = (): JoltClient | undefined => {
|
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
49
|
})
|
|
50
|
-
.then(
|
|
50
|
+
.then(res => res.data.id)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const { data: joltClient } = useQuery({
|
package/src/navigation/index.tsx
CHANGED
|
@@ -8,7 +8,7 @@ import React from 'react'
|
|
|
8
8
|
import { Icon } from '../components'
|
|
9
9
|
import { ConversationDetailsScreen } from '../screens/conversation_details_screen'
|
|
10
10
|
import { ConversationScreen } from '../screens/conversation_screen'
|
|
11
|
-
import { ConversationsScreen } from '../screens/conversations_screen'
|
|
11
|
+
import { ConversationsScreen } from '../screens/conversations/conversations_screen'
|
|
12
12
|
import { ConversationCreateScreen } from '../screens/create/conversation_create_screen'
|
|
13
13
|
import {
|
|
14
14
|
ConversationFilterReceipientsScreenOptions,
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
ConversationFiltersScreen,
|
|
28
28
|
ConversationFiltersScreenOptions,
|
|
29
29
|
} from '../screens/conversation_filters_screen'
|
|
30
|
+
import { ConversationFiltersParams } from '../screens/conversation_filters/screen_props'
|
|
30
31
|
|
|
31
32
|
export const CreateConversationStack = createNativeStackNavigator({
|
|
32
33
|
initialRouteName: 'ConversationSelectRecipients',
|
|
@@ -85,6 +86,23 @@ export const ChatStack = createNativeStackNavigator({
|
|
|
85
86
|
},
|
|
86
87
|
Conversation: {
|
|
87
88
|
screen: ConversationScreen,
|
|
89
|
+
options: ({ route, navigation }) => ({
|
|
90
|
+
headerTitle: (route.params as { title?: string })?.title ?? 'Chat',
|
|
91
|
+
headerLeft: props => (
|
|
92
|
+
<HeaderBackButton
|
|
93
|
+
displayMode="minimal"
|
|
94
|
+
onPress={() => {
|
|
95
|
+
if ((route.params as ConversationFiltersParams)?.chat_group_graph_id) {
|
|
96
|
+
// Ensure that conversations with a graph id pass them back to the conversation list
|
|
97
|
+
navigation.popTo('Conversations', route.params)
|
|
98
|
+
} else {
|
|
99
|
+
navigation.goBack()
|
|
100
|
+
}
|
|
101
|
+
}}
|
|
102
|
+
{...props}
|
|
103
|
+
/>
|
|
104
|
+
),
|
|
105
|
+
}),
|
|
88
106
|
},
|
|
89
107
|
ConversationDetails: {
|
|
90
108
|
screen: ConversationDetailsScreen,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useContext, useMemo } from 'react'
|
|
2
|
-
import { FlatList,
|
|
2
|
+
import { FlatList, StyleSheet, View, ViewStyle } from 'react-native'
|
|
3
3
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
4
4
|
import { Heading } from '../../../components'
|
|
5
5
|
import { useTheme } from '../../../hooks'
|
|
@@ -14,13 +14,22 @@ import { ConversationFilterStackParamList } from '../screen_props'
|
|
|
14
14
|
export type FilterProps = { group_source_app_name?: string; isActive: boolean; filter: FilterTypes }
|
|
15
15
|
|
|
16
16
|
export const FilterRow = ({ group_source_app_name, isActive, filter }: FilterProps) => {
|
|
17
|
-
const styles = useRowStyles()
|
|
17
|
+
const styles = useRowStyles({ isActive })
|
|
18
18
|
const { setAppFilter } = useContext(FilterContext)
|
|
19
19
|
|
|
20
20
|
return (
|
|
21
|
-
<PressableRow
|
|
21
|
+
<PressableRow
|
|
22
|
+
style={styles.row}
|
|
23
|
+
onPress={() => setAppFilter({ group_source_app_name })}
|
|
24
|
+
isActive={isActive}
|
|
25
|
+
>
|
|
22
26
|
<Text>{filter}</Text>
|
|
23
|
-
|
|
27
|
+
<Icon
|
|
28
|
+
name="general.check"
|
|
29
|
+
size={16}
|
|
30
|
+
style={styles.rowIconRight}
|
|
31
|
+
accessibilityElementsHidden
|
|
32
|
+
/>
|
|
24
33
|
</PressableRow>
|
|
25
34
|
)
|
|
26
35
|
}
|
|
@@ -31,7 +40,7 @@ export type GroupRowProps = {
|
|
|
31
40
|
}
|
|
32
41
|
|
|
33
42
|
export const GroupRow = ({ group, isActive }: GroupRowProps) => {
|
|
34
|
-
const styles = useRowStyles()
|
|
43
|
+
const styles = useRowStyles({ isActive })
|
|
35
44
|
const { setGroupFilter } = useContext(FilterContext)
|
|
36
45
|
|
|
37
46
|
const handleFilterByGroup = () => {
|
|
@@ -41,7 +50,7 @@ export const GroupRow = ({ group, isActive }: GroupRowProps) => {
|
|
|
41
50
|
const { headerImage, membershipsCount } = group
|
|
42
51
|
|
|
43
52
|
return (
|
|
44
|
-
<PressableRow style={styles.row} onPress={handleFilterByGroup}>
|
|
53
|
+
<PressableRow style={styles.row} onPress={handleFilterByGroup} isActive={isActive}>
|
|
45
54
|
{headerImage?.thumbnail && (
|
|
46
55
|
<Image
|
|
47
56
|
source={{ uri: headerImage?.thumbnail }}
|
|
@@ -50,13 +59,18 @@ export const GroupRow = ({ group, isActive }: GroupRowProps) => {
|
|
|
50
59
|
alt={`Image for ${group.name}`}
|
|
51
60
|
/>
|
|
52
61
|
)}
|
|
53
|
-
<View>
|
|
62
|
+
<View style={styles.rowContent}>
|
|
54
63
|
<Heading variant="h3" style={styles.rowTitle}>
|
|
55
64
|
{group.name}
|
|
56
65
|
</Heading>
|
|
57
66
|
{membershipsCount && <Text>{group.membershipsCount} members</Text>}
|
|
58
67
|
</View>
|
|
59
|
-
|
|
68
|
+
<Icon
|
|
69
|
+
name="general.check"
|
|
70
|
+
size={16}
|
|
71
|
+
style={styles.rowIconRight}
|
|
72
|
+
accessibilityElementsHidden
|
|
73
|
+
/>
|
|
60
74
|
</PressableRow>
|
|
61
75
|
)
|
|
62
76
|
}
|
|
@@ -67,12 +81,12 @@ export type TeamRowProps = {
|
|
|
67
81
|
}
|
|
68
82
|
|
|
69
83
|
export const TeamRow = ({ team }: TeamRowProps) => {
|
|
70
|
-
const styles = useRowStyles()
|
|
71
84
|
const { setGroupFilter } = useContext(FilterContext)
|
|
72
85
|
const servicesTeams = useServicesTeamsMap()
|
|
73
86
|
const { params } = useContext(FilterContext)
|
|
74
87
|
const { chat_group_graph_id } = params
|
|
75
88
|
const isActive = chat_group_graph_id === team.id.toString()
|
|
89
|
+
const styles = useRowStyles({ isActive })
|
|
76
90
|
|
|
77
91
|
const handleFilterByGroup = () => {
|
|
78
92
|
setGroupFilter({ chat_group_graph_id: team.id })
|
|
@@ -82,14 +96,19 @@ export const TeamRow = ({ team }: TeamRowProps) => {
|
|
|
82
96
|
const serviceTypeName = servicesTeam?.serviceTypeName || servicesTeam?.group
|
|
83
97
|
|
|
84
98
|
return (
|
|
85
|
-
<PressableRow style={styles.row} onPress={handleFilterByGroup}>
|
|
86
|
-
<View>
|
|
99
|
+
<PressableRow style={styles.row} onPress={handleFilterByGroup} isActive={isActive}>
|
|
100
|
+
<View style={styles.rowContent}>
|
|
87
101
|
<Heading variant="h3" style={styles.rowTitle}>
|
|
88
102
|
{team.name}
|
|
89
103
|
</Heading>
|
|
90
104
|
<Text>{serviceTypeName}</Text>
|
|
91
105
|
</View>
|
|
92
|
-
|
|
106
|
+
<Icon
|
|
107
|
+
name="general.check"
|
|
108
|
+
size={16}
|
|
109
|
+
style={styles.rowIconRight}
|
|
110
|
+
accessibilityElementsHidden
|
|
111
|
+
/>
|
|
93
112
|
</PressableRow>
|
|
94
113
|
)
|
|
95
114
|
}
|
|
@@ -109,12 +128,18 @@ export const ViewMore = ({ routeName }: ViewMoreRowProps) => {
|
|
|
109
128
|
|
|
110
129
|
export const PressableRow = ({
|
|
111
130
|
children,
|
|
131
|
+
isActive,
|
|
112
132
|
onPress,
|
|
113
133
|
style,
|
|
114
|
-
}: PropsWithChildren<{ onPress: () => void; style?: ViewStyle }>) => {
|
|
134
|
+
}: PropsWithChildren<{ isActive: boolean; onPress: () => void; style?: ViewStyle }>) => {
|
|
115
135
|
const styles = useRowStyles()
|
|
116
136
|
return (
|
|
117
|
-
<PlatformPressable
|
|
137
|
+
<PlatformPressable
|
|
138
|
+
style={styles.container}
|
|
139
|
+
onPress={onPress}
|
|
140
|
+
accessibilityRole="radio"
|
|
141
|
+
accessibilityState={{ selected: isActive }}
|
|
142
|
+
>
|
|
118
143
|
<View style={[styles.innerContainer, style]}>{children}</View>
|
|
119
144
|
</PlatformPressable>
|
|
120
145
|
)
|
|
@@ -124,7 +149,7 @@ const ASPECT_RATIO = 16 / 9
|
|
|
124
149
|
const THUMBNAIL_WIDTH = 80
|
|
125
150
|
const THUMBNAIL_HEIGHT = THUMBNAIL_WIDTH / ASPECT_RATIO
|
|
126
151
|
|
|
127
|
-
const useRowStyles = () => {
|
|
152
|
+
const useRowStyles = ({ isActive = false }: { isActive?: boolean } = {}) => {
|
|
128
153
|
const theme = useTheme()
|
|
129
154
|
return StyleSheet.create({
|
|
130
155
|
container: {
|
|
@@ -153,12 +178,17 @@ const useRowStyles = () => {
|
|
|
153
178
|
height: THUMBNAIL_HEIGHT,
|
|
154
179
|
borderRadius: 4,
|
|
155
180
|
},
|
|
181
|
+
rowContent: {
|
|
182
|
+
flexShrink: 1,
|
|
183
|
+
},
|
|
156
184
|
rowIconRight: {
|
|
157
185
|
marginLeft: 'auto',
|
|
158
186
|
color: theme.colors.statusSuccessIcon,
|
|
187
|
+
opacity: isActive ? 1 : 0,
|
|
159
188
|
},
|
|
160
189
|
rowTitle: {
|
|
161
190
|
fontSize: 16,
|
|
191
|
+
flexShrink: 1,
|
|
162
192
|
},
|
|
163
193
|
})
|
|
164
194
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
|
|
2
|
+
import React, { useCallback } from 'react'
|
|
3
|
+
import { StyleSheet, View } from 'react-native'
|
|
4
|
+
import { Badge } from '../../../components'
|
|
5
|
+
import { useApiGet } from '../../../hooks/use_api'
|
|
6
|
+
import { GroupResource } from '../../../types/resources/group_resource'
|
|
7
|
+
import { ConversationScreenProps } from '../conversations_screen'
|
|
8
|
+
|
|
9
|
+
export const ChatGroupBadge = () => {
|
|
10
|
+
const styles = useStyles()
|
|
11
|
+
const navigation = useNavigation()
|
|
12
|
+
const route = useRoute<RouteProp<ConversationScreenProps['route']>>()
|
|
13
|
+
const { chat_group_graph_id } = route.params || {}
|
|
14
|
+
const { data: group } = useApiGet<GroupResource>({
|
|
15
|
+
url: `/me/groups/${chat_group_graph_id}`,
|
|
16
|
+
data: {
|
|
17
|
+
fields: {
|
|
18
|
+
Group: [],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
enabled: !!chat_group_graph_id,
|
|
22
|
+
app: 'chat',
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const handleBadgePress = useCallback(() => {
|
|
26
|
+
navigation.setParams({
|
|
27
|
+
chat_group_graph_id: undefined,
|
|
28
|
+
group_source_app_name: undefined,
|
|
29
|
+
})
|
|
30
|
+
}, [navigation])
|
|
31
|
+
|
|
32
|
+
if (!group) return null
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<View style={styles.row}>
|
|
36
|
+
<Badge iconNameRight="general.x" label={group?.name || ''} onPress={handleBadgePress} />
|
|
37
|
+
</View>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const useStyles = () => {
|
|
42
|
+
return StyleSheet.create({
|
|
43
|
+
row: {
|
|
44
|
+
flexDirection: 'row',
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
}
|