@planningcenter/chat-react-native 3.24.0-rc.2 → 3.24.0-rc.4
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/primitive/form_sheet.d.ts +1 -1
- package/build/components/primitive/form_sheet.d.ts.map +1 -1
- package/build/components/primitive/form_sheet.js +1 -1
- package/build/components/primitive/form_sheet.js.map +1 -1
- package/build/hooks/index.d.ts +1 -0
- package/build/hooks/index.d.ts.map +1 -1
- package/build/hooks/index.js +1 -0
- package/build/hooks/index.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/hooks/use_new_conversation_entry.d.ts +3 -0
- package/build/hooks/use_new_conversation_entry.d.ts.map +1 -0
- package/build/hooks/use_new_conversation_entry.js +20 -0
- package/build/hooks/use_new_conversation_entry.js.map +1 -0
- package/build/hooks/use_report_message.d.ts +6 -0
- package/build/hooks/use_report_message.d.ts.map +1 -0
- package/build/hooks/use_report_message.js +28 -0
- package/build/hooks/use_report_message.js.map +1 -0
- package/build/navigation/index.d.ts +18 -8
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +16 -6
- package/build/navigation/index.js.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_new_entry_screen.d.ts +4 -0
- package/build/screens/conversation_select_recipients/conversation_new_entry_screen.d.ts.map +1 -0
- package/build/screens/conversation_select_recipients/conversation_new_entry_screen.js +67 -0
- package/build/screens/conversation_select_recipients/conversation_new_entry_screen.js.map +1 -0
- package/build/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.js +17 -2
- package/build/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.js.map +1 -1
- package/build/screens/conversation_select_type_screen.d.ts +11 -0
- package/build/screens/conversation_select_type_screen.d.ts.map +1 -0
- package/build/screens/conversation_select_type_screen.js +32 -0
- package/build/screens/conversation_select_type_screen.js.map +1 -0
- package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
- package/build/screens/conversations/components/list_header_component.js +18 -7
- package/build/screens/conversations/components/list_header_component.js.map +1 -1
- package/build/screens/index.d.ts +1 -1
- package/build/screens/index.d.ts.map +1 -1
- package/build/screens/index.js +1 -1
- package/build/screens/index.js.map +1 -1
- package/build/screens/message_actions_screen.js +9 -0
- package/build/screens/message_actions_screen.js.map +1 -1
- package/build/screens/message_report/components/message_preview.d.ts +10 -0
- package/build/screens/message_report/components/message_preview.d.ts.map +1 -0
- package/build/screens/message_report/components/message_preview.js +81 -0
- package/build/screens/message_report/components/message_preview.js.map +1 -0
- package/build/screens/message_report/components/report_reason_list.d.ts +9 -0
- package/build/screens/message_report/components/report_reason_list.d.ts.map +1 -0
- package/build/screens/message_report/components/report_reason_list.js +67 -0
- package/build/screens/message_report/components/report_reason_list.js.map +1 -0
- package/build/screens/message_report_screen.d.ts +10 -0
- package/build/screens/message_report_screen.d.ts.map +1 -0
- package/build/screens/message_report_screen.js +214 -0
- package/build/screens/message_report_screen.js.map +1 -0
- package/build/types/resources/message_report.d.ts +19 -0
- package/build/types/resources/message_report.d.ts.map +1 -0
- package/build/types/resources/message_report.js +9 -0
- package/build/types/resources/message_report.js.map +1 -0
- package/package.json +2 -2
- package/src/components/primitive/form_sheet.tsx +4 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use_features.ts +1 -0
- package/src/hooks/use_new_conversation_entry.ts +31 -0
- package/src/hooks/use_report_message.ts +37 -0
- package/src/navigation/index.tsx +19 -6
- package/src/screens/conversation_select_recipients/conversation_new_entry_screen.tsx +100 -0
- package/src/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.tsx +23 -3
- package/src/screens/conversation_select_type_screen.tsx +53 -0
- package/src/screens/conversations/components/list_header_component.tsx +20 -7
- package/src/screens/index.ts +1 -1
- package/src/screens/message_actions_screen.tsx +19 -0
- package/src/screens/message_report/components/message_preview.tsx +99 -0
- package/src/screens/message_report/components/report_reason_list.tsx +106 -0
- package/src/screens/message_report_screen.tsx +278 -0
- package/src/types/resources/message_report.ts +20 -0
- package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.d.ts +0 -4
- package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.d.ts.map +0 -1
- package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.js +0 -146
- package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.js.map +0 -1
- package/src/screens/conversation_select_recipients/conversation_select_recipients_screen.tsx +0 -215
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
import { Avatar, Text, Icon } from '../../../components';
|
|
4
|
+
import { useTheme } from '../../../hooks';
|
|
5
|
+
export function MessagePreview({ message, style }) {
|
|
6
|
+
const styles = useStyles();
|
|
7
|
+
const hasImages = message.attachments.some(att => att.type === 'MessageAttachment' && att.attributes?.contentType?.startsWith('image/'));
|
|
8
|
+
return (<View style={[styles.previewContainer, style]}>
|
|
9
|
+
<View style={styles.previewHeader}>
|
|
10
|
+
<Avatar sourceUri={message.author.avatar} size="md"/>
|
|
11
|
+
<Text style={styles.authorName}>{message.author.name}</Text>
|
|
12
|
+
</View>
|
|
13
|
+
|
|
14
|
+
<View style={styles.messageBubbleContainer}>
|
|
15
|
+
{message.text && (<View style={styles.messageBubble}>
|
|
16
|
+
<Text style={styles.messageText} numberOfLines={5}>
|
|
17
|
+
{message.text}
|
|
18
|
+
</Text>
|
|
19
|
+
</View>)}
|
|
20
|
+
|
|
21
|
+
{hasImages && (<View style={styles.imagePlaceholder}>
|
|
22
|
+
<Icon name="general.image" style={styles.placeholderIcon}/>
|
|
23
|
+
<Text variant="secondary" style={styles.placeholderText}>
|
|
24
|
+
Image hidden
|
|
25
|
+
</Text>
|
|
26
|
+
</View>)}
|
|
27
|
+
</View>
|
|
28
|
+
</View>);
|
|
29
|
+
}
|
|
30
|
+
const useStyles = () => {
|
|
31
|
+
const { colors } = useTheme();
|
|
32
|
+
return StyleSheet.create({
|
|
33
|
+
previewContainer: {
|
|
34
|
+
gap: 12,
|
|
35
|
+
},
|
|
36
|
+
previewHeader: {
|
|
37
|
+
flexDirection: 'row',
|
|
38
|
+
alignItems: 'center',
|
|
39
|
+
gap: 12,
|
|
40
|
+
},
|
|
41
|
+
authorName: {
|
|
42
|
+
fontSize: 14,
|
|
43
|
+
fontWeight: '600',
|
|
44
|
+
color: colors.textColorDefaultPrimary,
|
|
45
|
+
},
|
|
46
|
+
messageBubbleContainer: {
|
|
47
|
+
gap: 8,
|
|
48
|
+
},
|
|
49
|
+
messageBubble: {
|
|
50
|
+
backgroundColor: colors.fillColorNeutral060,
|
|
51
|
+
borderRadius: 16,
|
|
52
|
+
paddingHorizontal: 16,
|
|
53
|
+
paddingVertical: 12,
|
|
54
|
+
alignSelf: 'flex-start',
|
|
55
|
+
maxWidth: '80%',
|
|
56
|
+
},
|
|
57
|
+
messageText: {
|
|
58
|
+
fontSize: 14,
|
|
59
|
+
color: colors.textColorDefaultPrimary,
|
|
60
|
+
lineHeight: 20,
|
|
61
|
+
},
|
|
62
|
+
imagePlaceholder: {
|
|
63
|
+
height: 120,
|
|
64
|
+
backgroundColor: colors.fillColorNeutral060,
|
|
65
|
+
borderRadius: 16,
|
|
66
|
+
justifyContent: 'center',
|
|
67
|
+
alignItems: 'center',
|
|
68
|
+
gap: 8,
|
|
69
|
+
maxWidth: '80%',
|
|
70
|
+
alignSelf: 'flex-start',
|
|
71
|
+
},
|
|
72
|
+
placeholderIcon: {
|
|
73
|
+
fontSize: 32,
|
|
74
|
+
color: colors.iconColorDefaultSecondary,
|
|
75
|
+
},
|
|
76
|
+
placeholderText: {
|
|
77
|
+
fontSize: 14,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=message_preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message_preview.js","sourceRoot":"","sources":["../../../../src/screens/message_report/components/message_preview.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react'\nimport { View, StyleSheet, ViewStyle } from 'react-native'\nimport { Avatar, Text, Icon } from '../../../components'\nimport { useTheme } from '../../../hooks'\nimport { MessageResource } from '../../../types'\n\ninterface MessagePreviewProps {\n message: MessageResource\n style?: ViewStyle\n}\n\nexport function MessagePreview({ message, style }: MessagePreviewProps) {\n const styles = useStyles()\n\n const hasImages = message.attachments.some(\n att => att.type === 'MessageAttachment' && att.attributes?.contentType?.startsWith('image/')\n )\n\n return (\n <View style={[styles.previewContainer, style]}>\n <View style={styles.previewHeader}>\n <Avatar sourceUri={message.author.avatar} size=\"md\" />\n <Text style={styles.authorName}>{message.author.name}</Text>\n </View>\n\n <View style={styles.messageBubbleContainer}>\n {message.text && (\n <View style={styles.messageBubble}>\n <Text style={styles.messageText} numberOfLines={5}>\n {message.text}\n </Text>\n </View>\n )}\n\n {hasImages && (\n <View style={styles.imagePlaceholder}>\n <Icon name=\"general.image\" style={styles.placeholderIcon} />\n <Text variant=\"secondary\" style={styles.placeholderText}>\n Image hidden\n </Text>\n </View>\n )}\n </View>\n </View>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n previewContainer: {\n gap: 12,\n },\n previewHeader: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n },\n authorName: {\n fontSize: 14,\n fontWeight: '600',\n color: colors.textColorDefaultPrimary,\n },\n messageBubbleContainer: {\n gap: 8,\n },\n messageBubble: {\n backgroundColor: colors.fillColorNeutral060,\n borderRadius: 16,\n paddingHorizontal: 16,\n paddingVertical: 12,\n alignSelf: 'flex-start',\n maxWidth: '80%',\n },\n messageText: {\n fontSize: 14,\n color: colors.textColorDefaultPrimary,\n lineHeight: 20,\n },\n imagePlaceholder: {\n height: 120,\n backgroundColor: colors.fillColorNeutral060,\n borderRadius: 16,\n justifyContent: 'center',\n alignItems: 'center',\n gap: 8,\n maxWidth: '80%',\n alignSelf: 'flex-start',\n },\n placeholderIcon: {\n fontSize: 32,\n color: colors.iconColorDefaultSecondary,\n },\n placeholderText: {\n fontSize: 14,\n },\n })\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { MessageReportReason } from '../../../types/resources/message_report';
|
|
3
|
+
interface ReportReasonListProps {
|
|
4
|
+
selectedReason: MessageReportReason | null;
|
|
5
|
+
onReasonChange: (reason: MessageReportReason) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function ReportReasonList({ selectedReason, onReasonChange }: ReportReasonListProps): React.JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=report_reason_list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report_reason_list.d.ts","sourceRoot":"","sources":["../../../../src/screens/message_report/components/report_reason_list.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,EAEL,mBAAmB,EACpB,MAAM,yCAAyC,CAAA;AAOhD,UAAU,qBAAqB;IAC7B,cAAc,EAAE,mBAAmB,GAAG,IAAI,CAAA;IAC1C,cAAc,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAA;CACtD;AAED,wBAAgB,gBAAgB,CAAC,EAAE,cAAc,EAAE,cAAc,EAAE,EAAE,qBAAqB,qBAiBzF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
import { PlatformPressable } from '@react-navigation/elements';
|
|
4
|
+
import { Text } from '../../../components';
|
|
5
|
+
import { useTheme, useCreateAndroidRippleColor } from '../../../hooks';
|
|
6
|
+
import { Haptic } from '../../../utils/native_adapters';
|
|
7
|
+
import { MESSAGE_REPORT_REASONS, } from '../../../types/resources/message_report';
|
|
8
|
+
const MESSAGE_REPORT_REASONS_LIST = Object.entries(MESSAGE_REPORT_REASONS).map(([key, label]) => ({
|
|
9
|
+
key: key,
|
|
10
|
+
label,
|
|
11
|
+
}));
|
|
12
|
+
export function ReportReasonList({ selectedReason, onReasonChange }) {
|
|
13
|
+
return (<View>
|
|
14
|
+
{MESSAGE_REPORT_REASONS_LIST.map(({ key, label }) => (<ReportReasonButton key={key} reason={key} label={label} isSelected={selectedReason === key} onPress={() => {
|
|
15
|
+
Haptic.impactLight();
|
|
16
|
+
onReasonChange(key);
|
|
17
|
+
}}/>))}
|
|
18
|
+
</View>);
|
|
19
|
+
}
|
|
20
|
+
function ReportReasonButton({ label, isSelected, onPress }) {
|
|
21
|
+
const styles = useStyles({ isSelected });
|
|
22
|
+
const { colors } = useTheme();
|
|
23
|
+
const androidRippleColor = useCreateAndroidRippleColor({ color: colors.fillColorNeutral060 });
|
|
24
|
+
return (<PlatformPressable onPress={onPress} style={styles.pressable} android_ripple={{ color: androidRippleColor }} accessibilityRole="radio" accessibilityState={{ selected: isSelected }} accessibilityLabel={label}>
|
|
25
|
+
<View style={styles.row}>
|
|
26
|
+
<View style={styles.radioButton}>
|
|
27
|
+
{isSelected && <View style={styles.radioButtonInner}/>}
|
|
28
|
+
</View>
|
|
29
|
+
<Text style={styles.label}>{label}</Text>
|
|
30
|
+
</View>
|
|
31
|
+
</PlatformPressable>);
|
|
32
|
+
}
|
|
33
|
+
const useStyles = ({ isSelected }) => {
|
|
34
|
+
const { colors } = useTheme();
|
|
35
|
+
return StyleSheet.create({
|
|
36
|
+
pressable: {
|
|
37
|
+
paddingVertical: 16,
|
|
38
|
+
paddingHorizontal: 16,
|
|
39
|
+
},
|
|
40
|
+
row: {
|
|
41
|
+
flexDirection: 'row',
|
|
42
|
+
alignItems: 'center',
|
|
43
|
+
gap: 12,
|
|
44
|
+
},
|
|
45
|
+
radioButton: {
|
|
46
|
+
width: 20,
|
|
47
|
+
height: 20,
|
|
48
|
+
borderRadius: 10,
|
|
49
|
+
borderWidth: 2,
|
|
50
|
+
borderColor: isSelected ? colors.interaction : colors.borderColorDefaultBase,
|
|
51
|
+
justifyContent: 'center',
|
|
52
|
+
alignItems: 'center',
|
|
53
|
+
},
|
|
54
|
+
radioButtonInner: {
|
|
55
|
+
width: 10,
|
|
56
|
+
height: 10,
|
|
57
|
+
borderRadius: 5,
|
|
58
|
+
backgroundColor: colors.interaction,
|
|
59
|
+
},
|
|
60
|
+
label: {
|
|
61
|
+
fontSize: 16,
|
|
62
|
+
color: colors.textColorDefaultPrimary,
|
|
63
|
+
flex: 1,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=report_reason_list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report_reason_list.js","sourceRoot":"","sources":["../../../../src/screens/message_report/components/report_reason_list.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react'\nimport { View, StyleSheet } from 'react-native'\nimport { PlatformPressable } from '@react-navigation/elements'\nimport { Text } from '../../../components'\nimport { useTheme, useCreateAndroidRippleColor } from '../../../hooks'\nimport { Haptic } from '../../../utils/native_adapters'\nimport {\n MESSAGE_REPORT_REASONS,\n MessageReportReason,\n} from '../../../types/resources/message_report'\n\nconst MESSAGE_REPORT_REASONS_LIST = Object.entries(MESSAGE_REPORT_REASONS).map(([key, label]) => ({\n key: key as MessageReportReason,\n label,\n}))\n\ninterface ReportReasonListProps {\n selectedReason: MessageReportReason | null\n onReasonChange: (reason: MessageReportReason) => void\n}\n\nexport function ReportReasonList({ selectedReason, onReasonChange }: ReportReasonListProps) {\n return (\n <View>\n {MESSAGE_REPORT_REASONS_LIST.map(({ key, label }) => (\n <ReportReasonButton\n key={key}\n reason={key}\n label={label}\n isSelected={selectedReason === key}\n onPress={() => {\n Haptic.impactLight()\n onReasonChange(key)\n }}\n />\n ))}\n </View>\n )\n}\n\ninterface ReportReasonButtonProps {\n reason: MessageReportReason\n label: string\n isSelected: boolean\n onPress: () => void\n}\n\nfunction ReportReasonButton({ label, isSelected, onPress }: ReportReasonButtonProps) {\n const styles = useStyles({ isSelected })\n const { colors } = useTheme()\n const androidRippleColor = useCreateAndroidRippleColor({ color: colors.fillColorNeutral060 })\n\n return (\n <PlatformPressable\n onPress={onPress}\n style={styles.pressable}\n android_ripple={{ color: androidRippleColor }}\n accessibilityRole=\"radio\"\n accessibilityState={{ selected: isSelected }}\n accessibilityLabel={label}\n >\n <View style={styles.row}>\n <View style={styles.radioButton}>\n {isSelected && <View style={styles.radioButtonInner} />}\n </View>\n <Text style={styles.label}>{label}</Text>\n </View>\n </PlatformPressable>\n )\n}\n\nconst useStyles = ({ isSelected }: { isSelected: boolean }) => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n pressable: {\n paddingVertical: 16,\n paddingHorizontal: 16,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n },\n radioButton: {\n width: 20,\n height: 20,\n borderRadius: 10,\n borderWidth: 2,\n borderColor: isSelected ? colors.interaction : colors.borderColorDefaultBase,\n justifyContent: 'center',\n alignItems: 'center',\n },\n radioButtonInner: {\n width: 10,\n height: 10,\n borderRadius: 5,\n backgroundColor: colors.interaction,\n },\n label: {\n fontSize: 16,\n color: colors.textColorDefaultPrimary,\n flex: 1,\n },\n })\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { NativeStackNavigationOptions, NativeStackScreenProps } from '@react-navigation/native-stack';
|
|
3
|
+
import { StaticScreenProps } from '@react-navigation/native';
|
|
4
|
+
export declare const MessageReportScreenOptions: ({ navigation, }: NativeStackScreenProps<any>) => NativeStackNavigationOptions;
|
|
5
|
+
export type MessageReportScreenProps = StaticScreenProps<{
|
|
6
|
+
conversation_id: number;
|
|
7
|
+
message_id: string;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function MessageReportScreen({ route }: MessageReportScreenProps): React.JSX.Element | null;
|
|
10
|
+
//# sourceMappingURL=message_report_screen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message_report_screen.d.ts","sourceRoot":"","sources":["../../src/screens/message_report_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0D,MAAM,OAAO,CAAA;AAE9E,OAAO,KAAK,EACV,4BAA4B,EAC5B,sBAAsB,EACvB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,iBAAiB,EAA+B,MAAM,0BAA0B,CAAA;AAmBzF,eAAO,MAAM,0BAA0B,oBAEpC,sBAAsB,CAAC,GAAG,CAAC,KAAG,4BAI/B,CAAA;AAEF,MAAM,MAAM,wBAAwB,GAAG,iBAAiB,CAAC;IACvD,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AAEF,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,EAAE,wBAAwB,4BAStE"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import React, { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { View, StyleSheet, TextInput, ScrollView } from 'react-native';
|
|
3
|
+
import { useNavigation, StackActions } from '@react-navigation/native';
|
|
4
|
+
import { Spinner, Text, KeyboardView } from '../components';
|
|
5
|
+
import BlankState from '../components/primitive/blank_state_primitive';
|
|
6
|
+
import { useTheme } from '../hooks';
|
|
7
|
+
import { useReportMessage } from '../hooks/use_report_message';
|
|
8
|
+
import { HeaderDismissButton, HeaderTextButton, } from '../components/display/platform_modal_header_buttons';
|
|
9
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
10
|
+
import { useConversationMessages } from '../hooks/use_conversation_messages';
|
|
11
|
+
import { MessagePreview } from './message_report/components/message_preview';
|
|
12
|
+
import { ReportReasonList } from './message_report/components/report_reason_list';
|
|
13
|
+
import { platformFontWeightBold } from '../utils';
|
|
14
|
+
const MAX_DETAIL_LENGTH = 500;
|
|
15
|
+
export const MessageReportScreenOptions = ({ navigation, }) => ({
|
|
16
|
+
presentation: 'modal',
|
|
17
|
+
title: 'Report message',
|
|
18
|
+
headerLeft: () => <HeaderDismissButton title="Cancel" onPress={() => navigation.goBack()}/>,
|
|
19
|
+
});
|
|
20
|
+
export function MessageReportScreen({ route }) {
|
|
21
|
+
const { conversation_id, message_id } = route.params;
|
|
22
|
+
const { messages } = useConversationMessages({ conversation_id }, { refetchOnMount: false });
|
|
23
|
+
const message = messages.find(m => m.id === message_id);
|
|
24
|
+
if (!message)
|
|
25
|
+
return null;
|
|
26
|
+
return <MessageReportScreenContent message={message} conversation_id={conversation_id}/>;
|
|
27
|
+
}
|
|
28
|
+
function MessageReportScreenContent({ message, conversation_id, }) {
|
|
29
|
+
const styles = useStyles();
|
|
30
|
+
const navigation = useNavigation();
|
|
31
|
+
const [selectedReason, setSelectedReason] = useState(null);
|
|
32
|
+
const [reasonDetail, setReasonDetail] = useState('');
|
|
33
|
+
const { mutate: submitReport, status } = useReportMessage(conversation_id, message.id);
|
|
34
|
+
const handleReasonChange = useCallback((reason) => {
|
|
35
|
+
setSelectedReason(reason);
|
|
36
|
+
if (reason !== 'other') {
|
|
37
|
+
setReasonDetail('');
|
|
38
|
+
}
|
|
39
|
+
}, []);
|
|
40
|
+
const isFormValid = useMemo(() => {
|
|
41
|
+
if (selectedReason === null)
|
|
42
|
+
return false;
|
|
43
|
+
if (selectedReason === 'other' && reasonDetail.trim().length === 0) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
if (status === 'pending')
|
|
47
|
+
return false;
|
|
48
|
+
return true;
|
|
49
|
+
}, [selectedReason, reasonDetail, status]);
|
|
50
|
+
const handleSubmit = useCallback(() => {
|
|
51
|
+
if (!isFormValid || !selectedReason)
|
|
52
|
+
return;
|
|
53
|
+
submitReport({
|
|
54
|
+
reason: selectedReason,
|
|
55
|
+
reasonDetail: selectedReason === 'other' ? reasonDetail : undefined,
|
|
56
|
+
});
|
|
57
|
+
}, [isFormValid, selectedReason, reasonDetail, submitReport]);
|
|
58
|
+
const handleClose = useCallback(() => {
|
|
59
|
+
navigation.dispatch(StackActions.popTo('Conversation', { conversation_id }));
|
|
60
|
+
}, [navigation, conversation_id]);
|
|
61
|
+
const HeaderRight = useCallback(() => <HeaderTextButton title="Submit" onPress={handleSubmit} disabled={!isFormValid}/>, [handleSubmit, isFormValid]);
|
|
62
|
+
useLayoutEffect(() => {
|
|
63
|
+
if (status === 'pending' || status === 'success') {
|
|
64
|
+
navigation.setOptions({
|
|
65
|
+
headerRight: () => null,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
navigation.setOptions({
|
|
70
|
+
headerTitle: 'Report message',
|
|
71
|
+
headerRight: HeaderRight,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}, [HeaderRight, navigation, status]);
|
|
75
|
+
if (status === 'pending') {
|
|
76
|
+
return (<View style={styles.fullScreenContainer}>
|
|
77
|
+
<Spinner />
|
|
78
|
+
<Text style={styles.loadingText}>Submitting report...</Text>
|
|
79
|
+
</View>);
|
|
80
|
+
}
|
|
81
|
+
if (status === 'success') {
|
|
82
|
+
return (<View style={styles.fullScreenContainer}>
|
|
83
|
+
<BlankState.Root>
|
|
84
|
+
<BlankState.Imagery name="general.checkCircle" style={styles.successIcon}/>
|
|
85
|
+
<BlankState.Content>
|
|
86
|
+
<BlankState.Heading style={styles.successTitle}>Message reported</BlankState.Heading>
|
|
87
|
+
<BlankState.Text style={styles.successSubtitle}>
|
|
88
|
+
The message has been reported and a church leader will be contacted.
|
|
89
|
+
</BlankState.Text>
|
|
90
|
+
</BlankState.Content>
|
|
91
|
+
<BlankState.Button title="Close" onPress={handleClose} size="lg" variant="fill"/>
|
|
92
|
+
</BlankState.Root>
|
|
93
|
+
</View>);
|
|
94
|
+
}
|
|
95
|
+
if (status === 'error') {
|
|
96
|
+
return (<BlankState.Root>
|
|
97
|
+
<BlankState.Imagery name="general.exclamationTriangle"/>
|
|
98
|
+
<BlankState.Content>
|
|
99
|
+
<BlankState.Heading>Unable to submit report</BlankState.Heading>
|
|
100
|
+
<BlankState.Text>
|
|
101
|
+
We were unable to report this message. Please try again.
|
|
102
|
+
</BlankState.Text>
|
|
103
|
+
</BlankState.Content>
|
|
104
|
+
<BlankState.Button title="Close" onPress={handleClose} size="lg" variant="outline"/>
|
|
105
|
+
</BlankState.Root>);
|
|
106
|
+
}
|
|
107
|
+
return (<KeyboardView>
|
|
108
|
+
<ScrollView contentContainerStyle={styles.container}>
|
|
109
|
+
<Text style={styles.warningText}>
|
|
110
|
+
Reporting this message will notify a church leader. The person you are reporting will not
|
|
111
|
+
receive a notification from Church Center. If someone is in immediate danger, call local
|
|
112
|
+
emergency services. Don't wait.
|
|
113
|
+
</Text>
|
|
114
|
+
|
|
115
|
+
<MessagePreview message={message}/>
|
|
116
|
+
|
|
117
|
+
<View style={styles.reasonSection}>
|
|
118
|
+
<Text style={styles.fieldLabel}>
|
|
119
|
+
What best describes the problem? <Text style={styles.required}>*</Text>
|
|
120
|
+
</Text>
|
|
121
|
+
|
|
122
|
+
<View style={styles.reasonListContainer}>
|
|
123
|
+
<ReportReasonList selectedReason={selectedReason} onReasonChange={handleReasonChange}/>
|
|
124
|
+
</View>
|
|
125
|
+
</View>
|
|
126
|
+
|
|
127
|
+
{selectedReason === 'other' && (<View style={styles.detailSection}>
|
|
128
|
+
<Text style={styles.fieldLabel}>
|
|
129
|
+
Please provide more details <Text style={styles.required}>*</Text>
|
|
130
|
+
</Text>
|
|
131
|
+
<TextInput style={styles.textInput} multiline placeholder="Describe the issue..." value={reasonDetail} onChangeText={setReasonDetail} maxLength={MAX_DETAIL_LENGTH} accessibilityLabel="Additional details" accessibilityHint="Provide more information about why you're reporting this message"/>
|
|
132
|
+
{reasonDetail.length >= MAX_DETAIL_LENGTH - 100 && (<Text variant="footnote">
|
|
133
|
+
{reasonDetail.length}/{MAX_DETAIL_LENGTH}
|
|
134
|
+
</Text>)}
|
|
135
|
+
</View>)}
|
|
136
|
+
</ScrollView>
|
|
137
|
+
</KeyboardView>);
|
|
138
|
+
}
|
|
139
|
+
const useStyles = () => {
|
|
140
|
+
const { bottom } = useSafeAreaInsets();
|
|
141
|
+
const { colors } = useTheme();
|
|
142
|
+
return StyleSheet.create({
|
|
143
|
+
container: {
|
|
144
|
+
padding: 16,
|
|
145
|
+
paddingBottom: 16 + bottom,
|
|
146
|
+
gap: 24,
|
|
147
|
+
},
|
|
148
|
+
fullHeight: {
|
|
149
|
+
flex: 1,
|
|
150
|
+
justifyContent: 'center',
|
|
151
|
+
alignItems: 'center',
|
|
152
|
+
},
|
|
153
|
+
fullScreenContainer: {
|
|
154
|
+
flex: 1,
|
|
155
|
+
justifyContent: 'center',
|
|
156
|
+
alignItems: 'center',
|
|
157
|
+
backgroundColor: colors.surfaceColor100,
|
|
158
|
+
},
|
|
159
|
+
loadingText: {
|
|
160
|
+
marginTop: 16,
|
|
161
|
+
fontSize: 16,
|
|
162
|
+
fontWeight: '600',
|
|
163
|
+
color: colors.textColorDefaultPrimary,
|
|
164
|
+
},
|
|
165
|
+
warningText: {
|
|
166
|
+
fontSize: 14,
|
|
167
|
+
lineHeight: 20,
|
|
168
|
+
color: colors.textColorDefaultSecondary,
|
|
169
|
+
},
|
|
170
|
+
reasonSection: {
|
|
171
|
+
gap: 8,
|
|
172
|
+
},
|
|
173
|
+
fieldLabel: {
|
|
174
|
+
fontSize: 16,
|
|
175
|
+
fontWeight: platformFontWeightBold,
|
|
176
|
+
color: colors.textColorDefaultPrimary,
|
|
177
|
+
},
|
|
178
|
+
required: {
|
|
179
|
+
color: colors.statusErrorText,
|
|
180
|
+
},
|
|
181
|
+
reasonListContainer: {
|
|
182
|
+
backgroundColor: colors.surfaceColor100,
|
|
183
|
+
},
|
|
184
|
+
detailSection: {
|
|
185
|
+
gap: 8,
|
|
186
|
+
},
|
|
187
|
+
textInput: {
|
|
188
|
+
color: colors.textColorDefaultPrimary,
|
|
189
|
+
fontSize: 16,
|
|
190
|
+
textAlignVertical: 'top',
|
|
191
|
+
minHeight: 120,
|
|
192
|
+
maxHeight: 200,
|
|
193
|
+
borderWidth: 1,
|
|
194
|
+
borderColor: colors.borderColorDefaultBase,
|
|
195
|
+
borderRadius: 8,
|
|
196
|
+
paddingHorizontal: 16,
|
|
197
|
+
paddingVertical: 12,
|
|
198
|
+
backgroundColor: colors.surfaceColor100,
|
|
199
|
+
},
|
|
200
|
+
successIcon: {
|
|
201
|
+
color: colors.statusSuccessIcon,
|
|
202
|
+
fontSize: 48,
|
|
203
|
+
},
|
|
204
|
+
successTitle: {
|
|
205
|
+
fontSize: 24,
|
|
206
|
+
marginBottom: 4,
|
|
207
|
+
},
|
|
208
|
+
successSubtitle: {
|
|
209
|
+
fontSize: 16,
|
|
210
|
+
marginBottom: 4,
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
//# sourceMappingURL=message_report_screen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message_report_screen.js","sourceRoot":"","sources":["../../src/screens/message_report_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useCallback, useLayoutEffect, useMemo, useState } from 'react'\nimport { View, StyleSheet, TextInput, ScrollView } from 'react-native'\nimport type {\n NativeStackNavigationOptions,\n NativeStackScreenProps,\n} from '@react-navigation/native-stack'\nimport { StaticScreenProps, useNavigation, StackActions } from '@react-navigation/native'\nimport { Spinner, Text, KeyboardView } from '../components'\nimport BlankState from '../components/primitive/blank_state_primitive'\nimport { useTheme } from '../hooks'\nimport { useReportMessage } from '../hooks/use_report_message'\nimport {\n HeaderDismissButton,\n HeaderTextButton,\n} from '../components/display/platform_modal_header_buttons'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { useConversationMessages } from '../hooks/use_conversation_messages'\nimport { MessageResource } from '../types'\nimport { MessageReportReason } from '../types/resources/message_report'\nimport { MessagePreview } from './message_report/components/message_preview'\nimport { ReportReasonList } from './message_report/components/report_reason_list'\nimport { platformFontWeightBold } from '../utils'\n\nconst MAX_DETAIL_LENGTH = 500\n\nexport const MessageReportScreenOptions = ({\n navigation,\n}: NativeStackScreenProps<any>): NativeStackNavigationOptions => ({\n presentation: 'modal',\n title: 'Report message',\n headerLeft: () => <HeaderDismissButton title=\"Cancel\" onPress={() => navigation.goBack()} />,\n})\n\nexport type MessageReportScreenProps = StaticScreenProps<{\n conversation_id: number\n message_id: string\n}>\n\nexport function MessageReportScreen({ route }: MessageReportScreenProps) {\n const { conversation_id, message_id } = route.params\n\n const { messages } = useConversationMessages({ conversation_id }, { refetchOnMount: false })\n const message = messages.find(m => m.id === message_id)\n\n if (!message) return null\n\n return <MessageReportScreenContent message={message} conversation_id={conversation_id} />\n}\n\nfunction MessageReportScreenContent({\n message,\n conversation_id,\n}: {\n message: MessageResource\n conversation_id: number\n}) {\n const styles = useStyles()\n const navigation = useNavigation()\n const [selectedReason, setSelectedReason] = useState<MessageReportReason | null>(null)\n const [reasonDetail, setReasonDetail] = useState('')\n const { mutate: submitReport, status } = useReportMessage(conversation_id, message.id)\n\n const handleReasonChange = useCallback((reason: MessageReportReason) => {\n setSelectedReason(reason)\n\n if (reason !== 'other') {\n setReasonDetail('')\n }\n }, [])\n\n const isFormValid = useMemo(() => {\n if (selectedReason === null) return false\n\n if (selectedReason === 'other' && reasonDetail.trim().length === 0) {\n return false\n }\n\n if (status === 'pending') return false\n\n return true\n }, [selectedReason, reasonDetail, status])\n\n const handleSubmit = useCallback(() => {\n if (!isFormValid || !selectedReason) return\n\n submitReport({\n reason: selectedReason,\n reasonDetail: selectedReason === 'other' ? reasonDetail : undefined,\n })\n }, [isFormValid, selectedReason, reasonDetail, submitReport])\n\n const handleClose = useCallback(() => {\n navigation.dispatch(StackActions.popTo('Conversation', { conversation_id }))\n }, [navigation, conversation_id])\n\n const HeaderRight = useCallback(\n () => <HeaderTextButton title=\"Submit\" onPress={handleSubmit} disabled={!isFormValid} />,\n [handleSubmit, isFormValid]\n )\n\n useLayoutEffect(() => {\n if (status === 'pending' || status === 'success') {\n navigation.setOptions({\n headerRight: () => null,\n })\n } else {\n navigation.setOptions({\n headerTitle: 'Report message',\n headerRight: HeaderRight,\n })\n }\n }, [HeaderRight, navigation, status])\n\n if (status === 'pending') {\n return (\n <View style={styles.fullScreenContainer}>\n <Spinner />\n <Text style={styles.loadingText}>Submitting report...</Text>\n </View>\n )\n }\n\n if (status === 'success') {\n return (\n <View style={styles.fullScreenContainer}>\n <BlankState.Root>\n <BlankState.Imagery name=\"general.checkCircle\" style={styles.successIcon} />\n <BlankState.Content>\n <BlankState.Heading style={styles.successTitle}>Message reported</BlankState.Heading>\n <BlankState.Text style={styles.successSubtitle}>\n The message has been reported and a church leader will be contacted.\n </BlankState.Text>\n </BlankState.Content>\n <BlankState.Button title=\"Close\" onPress={handleClose} size=\"lg\" variant=\"fill\" />\n </BlankState.Root>\n </View>\n )\n }\n\n if (status === 'error') {\n return (\n <BlankState.Root>\n <BlankState.Imagery name=\"general.exclamationTriangle\" />\n <BlankState.Content>\n <BlankState.Heading>Unable to submit report</BlankState.Heading>\n <BlankState.Text>\n We were unable to report this message. Please try again.\n </BlankState.Text>\n </BlankState.Content>\n <BlankState.Button title=\"Close\" onPress={handleClose} size=\"lg\" variant=\"outline\" />\n </BlankState.Root>\n )\n }\n\n return (\n <KeyboardView>\n <ScrollView contentContainerStyle={styles.container}>\n <Text style={styles.warningText}>\n Reporting this message will notify a church leader. The person you are reporting will not\n receive a notification from Church Center. If someone is in immediate danger, call local\n emergency services. Don't wait.\n </Text>\n\n <MessagePreview message={message} />\n\n <View style={styles.reasonSection}>\n <Text style={styles.fieldLabel}>\n What best describes the problem? <Text style={styles.required}>*</Text>\n </Text>\n\n <View style={styles.reasonListContainer}>\n <ReportReasonList selectedReason={selectedReason} onReasonChange={handleReasonChange} />\n </View>\n </View>\n\n {selectedReason === 'other' && (\n <View style={styles.detailSection}>\n <Text style={styles.fieldLabel}>\n Please provide more details <Text style={styles.required}>*</Text>\n </Text>\n <TextInput\n style={styles.textInput}\n multiline\n placeholder=\"Describe the issue...\"\n value={reasonDetail}\n onChangeText={setReasonDetail}\n maxLength={MAX_DETAIL_LENGTH}\n accessibilityLabel=\"Additional details\"\n accessibilityHint=\"Provide more information about why you're reporting this message\"\n />\n {reasonDetail.length >= MAX_DETAIL_LENGTH - 100 && (\n <Text variant=\"footnote\">\n {reasonDetail.length}/{MAX_DETAIL_LENGTH}\n </Text>\n )}\n </View>\n )}\n </ScrollView>\n </KeyboardView>\n )\n}\n\nconst useStyles = () => {\n const { bottom } = useSafeAreaInsets()\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: {\n padding: 16,\n paddingBottom: 16 + bottom,\n gap: 24,\n },\n fullHeight: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n },\n fullScreenContainer: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: colors.surfaceColor100,\n },\n loadingText: {\n marginTop: 16,\n fontSize: 16,\n fontWeight: '600',\n color: colors.textColorDefaultPrimary,\n },\n warningText: {\n fontSize: 14,\n lineHeight: 20,\n color: colors.textColorDefaultSecondary,\n },\n reasonSection: {\n gap: 8,\n },\n fieldLabel: {\n fontSize: 16,\n fontWeight: platformFontWeightBold,\n color: colors.textColorDefaultPrimary,\n },\n required: {\n color: colors.statusErrorText,\n },\n reasonListContainer: {\n backgroundColor: colors.surfaceColor100,\n },\n detailSection: {\n gap: 8,\n },\n textInput: {\n color: colors.textColorDefaultPrimary,\n fontSize: 16,\n textAlignVertical: 'top',\n minHeight: 120,\n maxHeight: 200,\n borderWidth: 1,\n borderColor: colors.borderColorDefaultBase,\n borderRadius: 8,\n paddingHorizontal: 16,\n paddingVertical: 12,\n backgroundColor: colors.surfaceColor100,\n },\n successIcon: {\n color: colors.statusSuccessIcon,\n fontSize: 48,\n },\n successTitle: {\n fontSize: 24,\n marginBottom: 4,\n },\n successSubtitle: {\n fontSize: 16,\n marginBottom: 4,\n },\n })\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const MESSAGE_REPORT_REASONS: {
|
|
2
|
+
readonly scam_or_fraud: "Scam or fraud";
|
|
3
|
+
readonly inappropriate_content: "Inappropriate or offensive content";
|
|
4
|
+
readonly harassment_or_bullying: "Harassment or bullying";
|
|
5
|
+
readonly spam: "Spam or irrelevant messages";
|
|
6
|
+
readonly private_information: "Private or sensitive information shared";
|
|
7
|
+
readonly other: "Other (please specify)";
|
|
8
|
+
};
|
|
9
|
+
export type MessageReportReason = keyof typeof MESSAGE_REPORT_REASONS;
|
|
10
|
+
export interface MessageReportPayload {
|
|
11
|
+
data: {
|
|
12
|
+
type: 'MessageReport';
|
|
13
|
+
attributes: {
|
|
14
|
+
reason: MessageReportReason;
|
|
15
|
+
reason_detail?: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=message_report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message_report.d.ts","sourceRoot":"","sources":["../../../src/types/resources/message_report.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB;;;;;;;CAOzB,CAAA;AAEV,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,sBAAsB,CAAA;AAErE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,eAAe,CAAA;QACrB,UAAU,EAAE;YACV,MAAM,EAAE,mBAAmB,CAAA;YAC3B,aAAa,CAAC,EAAE,MAAM,CAAA;SACvB,CAAA;KACF,CAAA;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const MESSAGE_REPORT_REASONS = {
|
|
2
|
+
scam_or_fraud: 'Scam or fraud',
|
|
3
|
+
inappropriate_content: 'Inappropriate or offensive content',
|
|
4
|
+
harassment_or_bullying: 'Harassment or bullying',
|
|
5
|
+
spam: 'Spam or irrelevant messages',
|
|
6
|
+
private_information: 'Private or sensitive information shared',
|
|
7
|
+
other: 'Other (please specify)',
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=message_report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message_report.js","sourceRoot":"","sources":["../../../src/types/resources/message_report.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,aAAa,EAAE,eAAe;IAC9B,qBAAqB,EAAE,oCAAoC;IAC3D,sBAAsB,EAAE,wBAAwB;IAChD,IAAI,EAAE,6BAA6B;IACnC,mBAAmB,EAAE,yCAAyC;IAC9D,KAAK,EAAE,wBAAwB;CACvB,CAAA","sourcesContent":["export const MESSAGE_REPORT_REASONS = {\n scam_or_fraud: 'Scam or fraud',\n inappropriate_content: 'Inappropriate or offensive content',\n harassment_or_bullying: 'Harassment or bullying',\n spam: 'Spam or irrelevant messages',\n private_information: 'Private or sensitive information shared',\n other: 'Other (please specify)',\n} as const\n\nexport type MessageReportReason = keyof typeof MESSAGE_REPORT_REASONS\n\nexport interface MessageReportPayload {\n data: {\n type: 'MessageReport'\n attributes: {\n reason: MessageReportReason\n reason_detail?: string\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "3.24.0-rc.
|
|
3
|
+
"version": "3.24.0-rc.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"react-native-url-polyfill": "^2.0.0",
|
|
59
59
|
"typescript": "<5.6.0"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "005e3e542270b9e411f943d44ab2b2554cdbf2c6"
|
|
62
62
|
}
|
|
@@ -235,7 +235,7 @@ type FormSheetActionAppearanceUnion =
|
|
|
235
235
|
|
|
236
236
|
interface FormSheetActionProps {
|
|
237
237
|
title: string
|
|
238
|
-
iconName
|
|
238
|
+
iconName?: IconString
|
|
239
239
|
onPress: () => void
|
|
240
240
|
accessibilityLabel?: string
|
|
241
241
|
accessibilityHint?: string
|
|
@@ -265,7 +265,9 @@ function FormSheetAction({
|
|
|
265
265
|
style={styles.actionPressable}
|
|
266
266
|
disabled={disabled}
|
|
267
267
|
>
|
|
268
|
-
|
|
268
|
+
{iconName && (
|
|
269
|
+
<Icon name={iconName} size={16} accessibilityElementsHidden style={styles.actionIcon} />
|
|
270
|
+
)}
|
|
269
271
|
<Text style={styles.actionTitle}>{title}</Text>
|
|
270
272
|
</PlatformPressable>
|
|
271
273
|
)
|
package/src/hooks/index.ts
CHANGED
|
@@ -35,6 +35,7 @@ export function useFeatures() {
|
|
|
35
35
|
|
|
36
36
|
export const availableFeatures = {
|
|
37
37
|
threaded_replies: 'ROLLOUT_MOBILE_threaded_replies_v1',
|
|
38
|
+
message_reporting: 'ROLLOUT_MOBILE_message_reporting',
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
const stableEmptyFeatures: ApiCollection<FeatureResource> = {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import { useAppGrants } from './use_chat_permissions'
|
|
3
|
+
|
|
4
|
+
export type NewConversationEntryMode = 'select_type' | 'groups' | 'teams' | 'none'
|
|
5
|
+
|
|
6
|
+
export function useNewConversationEntry(): NewConversationEntryMode {
|
|
7
|
+
const appGrants = useAppGrants()
|
|
8
|
+
|
|
9
|
+
return useMemo(() => {
|
|
10
|
+
const canCreateGroupsConversations = appGrants.data?.some(
|
|
11
|
+
g => g.createConversations && g.appName === 'Groups'
|
|
12
|
+
)
|
|
13
|
+
const canCreateServicesConversations = appGrants.data?.some(
|
|
14
|
+
g => g.createConversations && g.appName === 'Services'
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
if (canCreateGroupsConversations && canCreateServicesConversations) {
|
|
18
|
+
return 'select_type'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (canCreateGroupsConversations) {
|
|
22
|
+
return 'groups'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (canCreateServicesConversations) {
|
|
26
|
+
return 'teams'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return 'none'
|
|
30
|
+
}, [appGrants.data])
|
|
31
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useMutation } from '@tanstack/react-query'
|
|
2
|
+
import { useApiClient } from './use_api_client'
|
|
3
|
+
import { Haptic } from '../utils/native_adapters'
|
|
4
|
+
import { MessageReportReason, MessageReportPayload } from '../types/resources/message_report'
|
|
5
|
+
|
|
6
|
+
export const useReportMessage = (conversationId: number, messageId: string) => {
|
|
7
|
+
const apiClient = useApiClient()
|
|
8
|
+
|
|
9
|
+
return useMutation({
|
|
10
|
+
mutationFn: async ({
|
|
11
|
+
reason,
|
|
12
|
+
reasonDetail,
|
|
13
|
+
}: {
|
|
14
|
+
reason: MessageReportReason
|
|
15
|
+
reasonDetail?: string
|
|
16
|
+
}) => {
|
|
17
|
+
const url = `/me/conversations/${conversationId}/messages/${messageId}/report`
|
|
18
|
+
const data: MessageReportPayload = {
|
|
19
|
+
data: {
|
|
20
|
+
type: 'MessageReport',
|
|
21
|
+
attributes: {
|
|
22
|
+
reason,
|
|
23
|
+
...(reasonDetail && { reason_detail: reasonDetail }),
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return apiClient.chat.post({ url, data })
|
|
29
|
+
},
|
|
30
|
+
onSuccess: () => {
|
|
31
|
+
Haptic.notificationSuccess()
|
|
32
|
+
},
|
|
33
|
+
onError: () => {
|
|
34
|
+
Haptic.notificationError()
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
}
|