@planningcenter/chat-react-native 3.24.0-rc.8 → 3.24.0

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.
Files changed (51) hide show
  1. package/build/components/display/platform_modal_header_buttons.d.ts +8 -0
  2. package/build/components/display/platform_modal_header_buttons.d.ts.map +1 -1
  3. package/build/components/display/platform_modal_header_buttons.js +8 -0
  4. package/build/components/display/platform_modal_header_buttons.js.map +1 -1
  5. package/build/navigation/index.d.ts +29 -79
  6. package/build/navigation/index.d.ts.map +1 -1
  7. package/build/navigation/index.js +20 -28
  8. package/build/navigation/index.js.map +1 -1
  9. package/build/screens/group_notification_settings_screen.d.ts +8 -0
  10. package/build/screens/group_notification_settings_screen.d.ts.map +1 -0
  11. package/build/screens/group_notification_settings_screen.js +79 -0
  12. package/build/screens/group_notification_settings_screen.js.map +1 -0
  13. package/build/screens/index.d.ts +1 -0
  14. package/build/screens/index.d.ts.map +1 -1
  15. package/build/screens/index.js +1 -0
  16. package/build/screens/index.js.map +1 -1
  17. package/build/screens/message_report/components/message_preview.d.ts.map +1 -1
  18. package/build/screens/message_report/components/message_preview.js +12 -19
  19. package/build/screens/message_report/components/message_preview.js.map +1 -1
  20. package/build/screens/notification_settings/hooks/groups.d.ts +94 -0
  21. package/build/screens/notification_settings/hooks/groups.d.ts.map +1 -0
  22. package/build/screens/notification_settings/hooks/groups.js +92 -0
  23. package/build/screens/notification_settings/hooks/groups.js.map +1 -0
  24. package/build/screens/notification_settings_screen.d.ts.map +1 -1
  25. package/build/screens/notification_settings_screen.js +50 -32
  26. package/build/screens/notification_settings_screen.js.map +1 -1
  27. package/build/screens/preferred_app_selection_screen.js +1 -1
  28. package/build/screens/preferred_app_selection_screen.js.map +1 -1
  29. package/build/types/resources/group_membership.d.ts +6 -0
  30. package/build/types/resources/group_membership.d.ts.map +1 -0
  31. package/build/types/resources/group_membership.js +2 -0
  32. package/build/types/resources/group_membership.js.map +1 -0
  33. package/build/types/resources/group_resource.d.ts +4 -0
  34. package/build/types/resources/group_resource.d.ts.map +1 -1
  35. package/build/types/resources/group_resource.js.map +1 -1
  36. package/build/types/resources/index.d.ts +2 -0
  37. package/build/types/resources/index.d.ts.map +1 -1
  38. package/build/types/resources/index.js +2 -0
  39. package/build/types/resources/index.js.map +1 -1
  40. package/package.json +2 -2
  41. package/src/components/display/platform_modal_header_buttons.tsx +16 -0
  42. package/src/navigation/index.tsx +27 -31
  43. package/src/screens/group_notification_settings_screen.tsx +92 -0
  44. package/src/screens/index.ts +1 -0
  45. package/src/screens/message_report/components/message_preview.tsx +15 -22
  46. package/src/screens/notification_settings/hooks/groups.ts +101 -0
  47. package/src/screens/notification_settings_screen.tsx +61 -34
  48. package/src/screens/preferred_app_selection_screen.tsx +1 -1
  49. package/src/types/resources/group_membership.ts +6 -0
  50. package/src/types/resources/group_resource.ts +5 -0
  51. package/src/types/resources/index.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"preferred_app_selection_screen.js","sourceRoot":"","sources":["../../src/screens/preferred_app_selection_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { PlatformPressable } from '@react-navigation/elements'\nimport { StaticScreenProps } from '@react-navigation/native'\nimport { useMutation } from '@tanstack/react-query'\nimport React, { type PropsWithChildren } from 'react'\nimport { Image, StyleSheet, View, type ViewStyle } from 'react-native'\nimport churchCenterLogo from '../../assets/churchCenter.png'\nimport servicesLogo from '../../assets/servicesApp.png'\nimport chatLogo from '../../assets/chatLogo.png'\nimport { Heading, Icon, Text } from '../components'\nimport { useApiClient, useTheme } from '../hooks'\nimport { PreferredApp, useChatTypes } from './preferred_app/hooks/use_chat_types'\nimport { useAppName } from '../hooks/use_app_name'\nimport { throwResponseError } from '../utils/response_error'\n\nexport type PreferredAppSelectionScreenProps = StaticScreenProps<{\n chatTypeId: number | string\n conversationType?: 'group' | 'team'\n currentSelection?: PreferredApp\n}>\n\nexport function PreferredAppSelectionScreen({ route }: PreferredAppSelectionScreenProps) {\n const { chatTypeId } = route.params\n const { data: chatTypes, refetch: refetchChatTypes } = useChatTypes()\n const appName = useAppName()\n\n const apiClient = useApiClient()\n\n const { mutate: updateChatType } = useMutation({\n throwOnError: true,\n onSuccess: () => refetchChatTypes(),\n mutationFn: (app: PreferredApp) => {\n return apiClient.chat\n .post({\n url: `/me/chat_types/${chatTypeId}/set_preferred_appz`,\n data: { data: { type: 'ChatType', attributes: { app } } },\n })\n .catch(throwResponseError)\n },\n })\n const chatType = chatTypes.find(t => t.id === chatTypeId)\n const { preferredAppOptions } = chatType || {}\n\n const handleSelection = (app: PreferredApp) => {\n updateChatType(app)\n }\n\n const sectionTitle = `${chatType?.title} Conversations`\n\n return (\n <View style={styles.container}>\n <View style={styles.section}>\n <Heading variant=\"h3\" style={styles.sectionHeading}>\n {sectionTitle}\n </Heading>\n {preferredAppOptions?.sort(sortPreferredApp('asc')).map((option, key) => (\n <PressableRow\n key={`${key}-${option}`}\n isActive={chatType?.preferredApp === option}\n onPress={() => handleSelection(option)}\n >\n <Image source={getAppImage(option)} style={styles.logo} />\n <Text>\n {option}\n {appName.includes(option.replace(/\\s/, '').toLowerCase()) ? ' ( current )' : ''}\n </Text>\n </PressableRow>\n ))}\n </View>\n </View>\n )\n}\n\nconst sortPreferredApp = (dir?: 'asc' | 'desc') => (a: PreferredApp, b: PreferredApp) => {\n if (a === 'None') return 1\n if (a > b) return dir === 'asc' ? 1 : -1\n if (b > a) return dir === 'asc' ? -1 : 1\n\n return 0\n}\n\nconst getAppImage = (option: PreferredApp) => {\n switch (option) {\n case 'Church Center':\n return churchCenterLogo\n case 'Services':\n return servicesLogo\n case 'Chat':\n return chatLogo\n default:\n return undefined\n }\n}\n\nconst PressableRow = ({\n children,\n isActive,\n onPress,\n style,\n}: PropsWithChildren<{ isActive: boolean; onPress: () => void; style?: ViewStyle }>) => {\n const styles = useRowStyles({ isActive })\n return (\n <PlatformPressable\n style={styles.pressable}\n onPress={onPress}\n accessibilityRole=\"radio\"\n accessibilityState={{ selected: isActive }}\n >\n <View style={styles.row}>\n <View style={[styles.rowInner, style]}>{children}</View>\n <Icon\n name=\"general.check\"\n style={styles.rowIconRight}\n accessibilityElementsHidden\n maxFontSizeMultiplier={2.5}\n />\n </View>\n </PlatformPressable>\n )\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n },\n section: {\n paddingTop: 16,\n },\n sectionHeading: {\n paddingHorizontal: 16,\n paddingBottom: 4,\n },\n logo: {\n width: 32,\n height: 32,\n borderRadius: 8,\n },\n})\n\nconst useRowStyles = ({ isActive = false }: { isActive?: boolean } = {}) => {\n const theme = useTheme()\n\n return StyleSheet.create({\n pressable: {\n paddingLeft: 16,\n backgroundColor: theme.colors.surfaceColor100,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 12,\n borderBottomWidth: 1,\n borderBottomColor: theme.colors.borderColorDefaultBase,\n paddingVertical: 12,\n paddingRight: 16,\n },\n rowInner: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n flexShrink: 1,\n },\n rowIconRight: {\n fontSize: 16,\n color: theme.colors.statusSuccessIcon,\n opacity: isActive ? 1 : 0,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"preferred_app_selection_screen.js","sourceRoot":"","sources":["../../src/screens/preferred_app_selection_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { PlatformPressable } from '@react-navigation/elements'\nimport { StaticScreenProps } from '@react-navigation/native'\nimport { useMutation } from '@tanstack/react-query'\nimport React, { type PropsWithChildren } from 'react'\nimport { Image, StyleSheet, View, type ViewStyle } from 'react-native'\nimport churchCenterLogo from '../../assets/churchCenter.png'\nimport servicesLogo from '../../assets/servicesApp.png'\nimport chatLogo from '../../assets/chatLogo.png'\nimport { Heading, Icon, Text } from '../components'\nimport { useApiClient, useTheme } from '../hooks'\nimport { PreferredApp, useChatTypes } from './preferred_app/hooks/use_chat_types'\nimport { useAppName } from '../hooks/use_app_name'\nimport { throwResponseError } from '../utils/response_error'\n\nexport type PreferredAppSelectionScreenProps = StaticScreenProps<{\n chatTypeId: number | string\n conversationType?: 'group' | 'team'\n currentSelection?: PreferredApp\n}>\n\nexport function PreferredAppSelectionScreen({ route }: PreferredAppSelectionScreenProps) {\n const { chatTypeId } = route.params\n const { data: chatTypes, refetch: refetchChatTypes } = useChatTypes()\n const appName = useAppName()\n\n const apiClient = useApiClient()\n\n const { mutate: updateChatType } = useMutation({\n throwOnError: true,\n onSuccess: () => refetchChatTypes(),\n mutationFn: (app: PreferredApp) => {\n return apiClient.chat\n .post({\n url: `/me/chat_types/${chatTypeId}/set_preferred_app`,\n data: { data: { type: 'ChatType', attributes: { app } } },\n })\n .catch(throwResponseError)\n },\n })\n const chatType = chatTypes.find(t => t.id === chatTypeId)\n const { preferredAppOptions } = chatType || {}\n\n const handleSelection = (app: PreferredApp) => {\n updateChatType(app)\n }\n\n const sectionTitle = `${chatType?.title} Conversations`\n\n return (\n <View style={styles.container}>\n <View style={styles.section}>\n <Heading variant=\"h3\" style={styles.sectionHeading}>\n {sectionTitle}\n </Heading>\n {preferredAppOptions?.sort(sortPreferredApp('asc')).map((option, key) => (\n <PressableRow\n key={`${key}-${option}`}\n isActive={chatType?.preferredApp === option}\n onPress={() => handleSelection(option)}\n >\n <Image source={getAppImage(option)} style={styles.logo} />\n <Text>\n {option}\n {appName.includes(option.replace(/\\s/, '').toLowerCase()) ? ' ( current )' : ''}\n </Text>\n </PressableRow>\n ))}\n </View>\n </View>\n )\n}\n\nconst sortPreferredApp = (dir?: 'asc' | 'desc') => (a: PreferredApp, b: PreferredApp) => {\n if (a === 'None') return 1\n if (a > b) return dir === 'asc' ? 1 : -1\n if (b > a) return dir === 'asc' ? -1 : 1\n\n return 0\n}\n\nconst getAppImage = (option: PreferredApp) => {\n switch (option) {\n case 'Church Center':\n return churchCenterLogo\n case 'Services':\n return servicesLogo\n case 'Chat':\n return chatLogo\n default:\n return undefined\n }\n}\n\nconst PressableRow = ({\n children,\n isActive,\n onPress,\n style,\n}: PropsWithChildren<{ isActive: boolean; onPress: () => void; style?: ViewStyle }>) => {\n const styles = useRowStyles({ isActive })\n return (\n <PlatformPressable\n style={styles.pressable}\n onPress={onPress}\n accessibilityRole=\"radio\"\n accessibilityState={{ selected: isActive }}\n >\n <View style={styles.row}>\n <View style={[styles.rowInner, style]}>{children}</View>\n <Icon\n name=\"general.check\"\n style={styles.rowIconRight}\n accessibilityElementsHidden\n maxFontSizeMultiplier={2.5}\n />\n </View>\n </PlatformPressable>\n )\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n },\n section: {\n paddingTop: 16,\n },\n sectionHeading: {\n paddingHorizontal: 16,\n paddingBottom: 4,\n },\n logo: {\n width: 32,\n height: 32,\n borderRadius: 8,\n },\n})\n\nconst useRowStyles = ({ isActive = false }: { isActive?: boolean } = {}) => {\n const theme = useTheme()\n\n return StyleSheet.create({\n pressable: {\n paddingLeft: 16,\n backgroundColor: theme.colors.surfaceColor100,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 12,\n borderBottomWidth: 1,\n borderBottomColor: theme.colors.borderColorDefaultBase,\n paddingVertical: 12,\n paddingRight: 16,\n },\n rowInner: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n flexShrink: 1,\n },\n rowIconRight: {\n fontSize: 16,\n color: theme.colors.statusSuccessIcon,\n opacity: isActive ? 1 : 0,\n },\n })\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import { ResourceObject } from '../api_primitives';
2
+ export interface GroupMembership extends ResourceObject {
3
+ notificationLevel: string;
4
+ notificationLevelDescription: string;
5
+ }
6
+ //# sourceMappingURL=group_membership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group_membership.d.ts","sourceRoot":"","sources":["../../../src/types/resources/group_membership.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,iBAAiB,EAAE,MAAM,CAAA;IACzB,4BAA4B,EAAE,MAAM,CAAA;CACrC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=group_membership.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group_membership.js","sourceRoot":"","sources":["../../../src/types/resources/group_membership.ts"],"names":[],"mappings":"","sourcesContent":["import { ResourceObject } from '../api_primitives'\n\nexport interface GroupMembership extends ResourceObject {\n notificationLevel: string\n notificationLevelDescription: string\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { AppName } from './app_name';
2
+ import { GroupMembership } from './group_membership';
2
3
  export type SourceType = 'Team' | 'Group' | 'PlanTeam';
3
4
  export type GraphId = `${AppName}-${SourceType}-${number}`;
4
5
  export interface GroupResource {
@@ -11,4 +12,7 @@ export interface GroupResource {
11
12
  sourceAppName: AppName;
12
13
  sourceType: SourceType;
13
14
  }
15
+ export interface GroupResourceWithMembership extends GroupResource {
16
+ myGroupMembership?: GroupMembership;
17
+ }
14
18
  //# sourceMappingURL=group_resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"group_resource.d.ts","sourceRoot":"","sources":["../../../src/types/resources/group_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAA;AACtD,MAAM,MAAM,OAAO,GAAG,GAAG,OAAO,IAAI,UAAU,IAAI,MAAM,EAAE,CAAA;AAE1D,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAA;IACX,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,aAAa,EAAE,OAAO,CAAA;IACtB,UAAU,EAAE,UAAU,CAAA;CACvB"}
1
+ {"version":3,"file":"group_resource.d.ts","sourceRoot":"","sources":["../../../src/types/resources/group_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEpD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAA;AACtD,MAAM,MAAM,OAAO,GAAG,GAAG,OAAO,IAAI,UAAU,IAAI,MAAM,EAAE,CAAA;AAE1D,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAA;IACX,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,aAAa,EAAE,OAAO,CAAA;IACtB,UAAU,EAAE,UAAU,CAAA;CACvB;AAED,MAAM,WAAW,2BAA4B,SAAQ,aAAa;IAChE,iBAAiB,CAAC,EAAE,eAAe,CAAA;CACpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"group_resource.js","sourceRoot":"","sources":["../../../src/types/resources/group_resource.ts"],"names":[],"mappings":"","sourcesContent":["import { AppName } from './app_name'\n\nexport type SourceType = 'Team' | 'Group' | 'PlanTeam'\nexport type GraphId = `${AppName}-${SourceType}-${number}`\n\nexport interface GroupResource {\n id: GraphId\n type: 'Group'\n links: { self: string }\n name: string | null\n sourceAppName: AppName\n sourceType: SourceType\n}\n"]}
1
+ {"version":3,"file":"group_resource.js","sourceRoot":"","sources":["../../../src/types/resources/group_resource.ts"],"names":[],"mappings":"","sourcesContent":["import { AppName } from './app_name'\nimport { GroupMembership } from './group_membership'\n\nexport type SourceType = 'Team' | 'Group' | 'PlanTeam'\nexport type GraphId = `${AppName}-${SourceType}-${number}`\n\nexport interface GroupResource {\n id: GraphId\n type: 'Group'\n links: { self: string }\n name: string | null\n sourceAppName: AppName\n sourceType: SourceType\n}\n\nexport interface GroupResourceWithMembership extends GroupResource {\n myGroupMembership?: GroupMembership\n}\n"]}
@@ -8,4 +8,6 @@ export * from './groups';
8
8
  export * from './app_grant';
9
9
  export * from './services';
10
10
  export * from './organization';
11
+ export * from './group_membership';
12
+ export * from './group_resource';
11
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA"}
@@ -8,4 +8,6 @@ export * from './groups';
8
8
  export * from './app_grant';
9
9
  export * from './services';
10
10
  export * from './organization';
11
+ export * from './group_membership';
12
+ export * from './group_resource';
11
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA","sourcesContent":["export * from './analytics_metadata'\nexport * from './conversation'\nexport * from './member'\nexport * from './message'\nexport * from './oauth_token'\nexport * from './person'\nexport * from './groups'\nexport * from './app_grant'\nexport * from './services'\nexport * from './organization'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA","sourcesContent":["export * from './analytics_metadata'\nexport * from './conversation'\nexport * from './member'\nexport * from './message'\nexport * from './oauth_token'\nexport * from './person'\nexport * from './groups'\nexport * from './app_grant'\nexport * from './services'\nexport * from './organization'\nexport * from './group_membership'\nexport * from './group_resource'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.24.0-rc.8",
3
+ "version": "3.24.0",
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": "6259e50e7b8ca70aee8b50cc641bc3a6c2d6c11a"
61
+ "gitHead": "766e0c2895aed482fffb467e07439de8cc6d2253"
62
62
  }
@@ -3,6 +3,7 @@ import { TextButton } from './text_button'
3
3
  import { HeaderButton } from '@react-navigation/elements'
4
4
  import { Icon } from './icon'
5
5
  import { useTheme } from '../../hooks'
6
+ import type { NativeStackHeaderRightProps } from '@react-navigation/native-stack'
6
7
 
7
8
  interface HeaderTextButtonProps {
8
9
  onPress: () => void
@@ -62,6 +63,21 @@ export const HeaderDismissButton = ({
62
63
  })
63
64
  }
64
65
 
66
+ interface HeaderDoneButtonProps extends NativeStackHeaderRightProps {
67
+ navigation: { goBack: () => void; getState: () => any }
68
+ }
69
+
70
+ export const HeaderDoneButton = ({ navigation, ...props }: HeaderDoneButtonProps) => {
71
+ const state = navigation.getState()
72
+ const isFirstScreen = state.index === 0
73
+
74
+ if (!isFirstScreen) {
75
+ return null
76
+ }
77
+
78
+ return <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
79
+ }
80
+
65
81
  const useStyles = () => {
66
82
  const { colors } = useTheme()
67
83
 
@@ -8,7 +8,10 @@ import { CardStyleInterpolators } from '@react-navigation/stack'
8
8
  import React from 'react'
9
9
  import { Platform } from 'react-native'
10
10
  import { Icon } from '../components'
11
- import { HeaderTextButton } from '../components/display/platform_modal_header_buttons'
11
+ import {
12
+ HeaderDoneButton,
13
+ HeaderTextButton,
14
+ } from '../components/display/platform_modal_header_buttons'
12
15
  import {
13
16
  AttachmentActionsScreen,
14
17
  AttachmentActionsScreenOptions,
@@ -51,6 +54,7 @@ import { MessageReportScreen, MessageReportScreenOptions } from '../screens/mess
51
54
  import { NotFound } from '../screens/not_found'
52
55
  import { NotificationSettingsScreen } from '../screens/notification_settings_screen'
53
56
  import { PreferredAppSelectionScreen } from '../screens/preferred_app_selection_screen'
57
+ import { GroupNotificationSettingsScreen } from '../screens/group_notification_settings_screen'
54
58
  import { ReactionsScreen, ReactionsScreenOptions } from '../screens/reactions_screen'
55
59
  import { ScreenLayoutWithChatAccessGate } from './screenLayout'
56
60
  import { SendGiphyScreen, SendGiphyScreenOptions } from '../screens/send_giphy_screen'
@@ -126,32 +130,6 @@ export const NewConversationStack = createNativeStackNavigator({
126
130
  },
127
131
  })
128
132
 
129
- export const NotificationSettingsStack = createNativeStackNavigator({
130
- initialRouteName: 'NotificationSettings',
131
- screenOptions: {
132
- headerBackButtonDisplayMode: 'minimal',
133
- },
134
- screenLayout: ScreenLayoutWithChatAccessGate,
135
- screens: {
136
- NotificationSettings: {
137
- screen: NotificationSettingsScreen,
138
- options: ({ navigation }) => ({
139
- title: 'Chat',
140
- headerRight: (props: NativeStackHeaderRightProps) => (
141
- <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
142
- ),
143
- headerBackVisible: false,
144
- }),
145
- },
146
- PreferredAppSelection: {
147
- screen: PreferredAppSelectionScreen,
148
- options: {
149
- title: 'Preferred app',
150
- },
151
- },
152
- },
153
- })
154
-
155
133
  export const ChatStack = createNativeStackNavigator({
156
134
  screenOptions: {
157
135
  headerBackButtonDisplayMode: 'minimal',
@@ -251,13 +229,31 @@ export const ChatStack = createNativeStackNavigator({
251
229
  ),
252
230
  }),
253
231
  },
254
- NotificationSettingsStack: {
255
- screen: NotificationSettingsStack,
232
+ NotificationSettings: {
233
+ screen: NotificationSettingsScreen,
234
+ options: ({ navigation }) => ({
235
+ title: 'Chat',
236
+ headerBackVisible: false,
237
+ headerRight: (props: NativeStackHeaderRightProps) => (
238
+ <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
239
+ ),
240
+ }),
241
+ },
242
+ PreferredAppSelection: {
243
+ screen: PreferredAppSelectionScreen,
256
244
  options: {
257
- headerShown: false,
258
- presentation: 'modal',
245
+ title: 'Preferred app',
259
246
  },
260
247
  },
248
+ GroupNotificationSettings: {
249
+ screen: GroupNotificationSettingsScreen,
250
+ options: ({ route, navigation }) => ({
251
+ title: (route.params as { title?: string })?.title || 'Group Settings',
252
+ headerRight: (props: NativeStackHeaderRightProps) => (
253
+ <HeaderDoneButton {...props} navigation={navigation} />
254
+ ),
255
+ }),
256
+ },
261
257
  New: {
262
258
  screen: NewConversationStack,
263
259
  if: useQualifiedByAge,
@@ -0,0 +1,92 @@
1
+ import { StaticScreenProps, useNavigation } from '@react-navigation/native'
2
+ import React, { useEffect } from 'react'
3
+ import { StyleSheet, View } from 'react-native'
4
+ import { Heading, Switch, Text } from '../components'
5
+ import { useTheme } from '../hooks'
6
+ import { platformFontWeightBold } from '../utils/styles'
7
+ import { useGroup, useGroupMembershipUpdate } from './notification_settings/hooks/groups'
8
+
9
+ export type GroupNotificationSettingsScreenProps = StaticScreenProps<{
10
+ groupId: number | string
11
+ title: string
12
+ }>
13
+
14
+ export function GroupNotificationSettingsScreen({ route }: GroupNotificationSettingsScreenProps) {
15
+ const { groupId, title } = route.params
16
+ const navigation = useNavigation()
17
+ const styles = useStyles()
18
+ const { data: group } = useGroup({ groupId })
19
+ const { mutate: updateNotificationLevel } = useGroupMembershipUpdate({ groupId })
20
+
21
+ const notificationsEnabled = group.myGroupMembership?.notificationLevel === 'everything'
22
+
23
+ useEffect(() => {
24
+ if (!group.name || title === group.name) return
25
+
26
+ navigation.setOptions({ title: group.name })
27
+ }, [group.name, title, navigation])
28
+
29
+ const handleToggle = (value: boolean) => {
30
+ const notificationLevel = value ? 'everything' : 'nothing'
31
+ updateNotificationLevel(notificationLevel)
32
+ }
33
+
34
+ return (
35
+ <View style={styles.container}>
36
+ <View style={styles.sectionOuter}>
37
+ <View style={styles.sectionInner}>
38
+ <Heading variant="h3" style={styles.sectionHeading}>
39
+ Group notification settings
40
+ </Heading>
41
+ <Text variant="tertiary" style={styles.sectionSubtitle}>
42
+ The settings are applied to all conversations in{' '}
43
+ <Text style={styles.groupNameBold}>{group.name || title}</Text>
44
+ </Text>
45
+ </View>
46
+ </View>
47
+ <View style={styles.settingRow}>
48
+ <Text>Enable notifications</Text>
49
+ <Switch value={notificationsEnabled} onValueChange={handleToggle} />
50
+ </View>
51
+ </View>
52
+ )
53
+ }
54
+
55
+ const useStyles = () => {
56
+ const { colors } = useTheme()
57
+
58
+ return StyleSheet.create({
59
+ container: {
60
+ flex: 1,
61
+ backgroundColor: colors.surfaceColor100,
62
+ },
63
+ sectionOuter: {
64
+ paddingLeft: 16,
65
+ backgroundColor: colors.surfaceColor100,
66
+ },
67
+ sectionInner: {
68
+ paddingRight: 16,
69
+ paddingTop: 16,
70
+ paddingBottom: 12,
71
+ borderBottomWidth: 1,
72
+ borderBottomColor: colors.borderColorDefaultBase,
73
+ },
74
+ sectionHeading: {
75
+ paddingBottom: 4,
76
+ },
77
+ sectionSubtitle: {
78
+ color: colors.textColorDefaultSecondary,
79
+ },
80
+ groupNameBold: {
81
+ fontWeight: platformFontWeightBold,
82
+ },
83
+ settingRow: {
84
+ flexDirection: 'row',
85
+ justifyContent: 'space-between',
86
+ alignItems: 'center',
87
+ paddingHorizontal: 16,
88
+ paddingVertical: 12,
89
+ backgroundColor: colors.surfaceColor100,
90
+ },
91
+ })
92
+ }
@@ -4,6 +4,7 @@ export * from './conversation_screen'
4
4
  export * from './conversation_new/conversation_new_screen'
5
5
  export * from './notification_settings_screen'
6
6
  export * from './preferred_app_selection_screen'
7
+ export * from './group_notification_settings_screen'
7
8
  export * from './conversation_filter_recipients/conversation_filter_recipients_screen'
8
9
  export * from './message_actions_screen'
9
10
  export * from './message_report_screen'
@@ -10,12 +10,13 @@ interface MessagePreviewProps {
10
10
  }
11
11
 
12
12
  export function MessagePreview({ message, style }: MessagePreviewProps) {
13
- const styles = useStyles()
14
-
15
13
  const hasImages = message.attachments.some(
16
14
  att => att.type === 'MessageAttachment' && att.attributes?.contentType?.startsWith('image/')
17
15
  )
18
16
 
17
+ const imageOnly = hasImages && !message.text
18
+ const styles = useStyles({ imageOnly })
19
+
19
20
  return (
20
21
  <View style={[styles.previewContainer, style]}>
21
22
  <View style={styles.previewHeader}>
@@ -23,15 +24,7 @@ export function MessagePreview({ message, style }: MessagePreviewProps) {
23
24
  <Text style={styles.authorName}>{message.author.name}</Text>
24
25
  </View>
25
26
 
26
- <View style={styles.messageBubbleContainer}>
27
- {message.text && (
28
- <View style={styles.messageBubble}>
29
- <Text style={styles.messageText} numberOfLines={5}>
30
- {message.text}
31
- </Text>
32
- </View>
33
- )}
34
-
27
+ <View style={styles.messageBubble}>
35
28
  {hasImages && (
36
29
  <View style={styles.imagePlaceholder}>
37
30
  <Icon name="general.image" style={styles.placeholderIcon} />
@@ -40,12 +33,18 @@ export function MessagePreview({ message, style }: MessagePreviewProps) {
40
33
  </Text>
41
34
  </View>
42
35
  )}
36
+
37
+ {message.text && (
38
+ <Text style={styles.messageText} numberOfLines={5}>
39
+ {message.text}
40
+ </Text>
41
+ )}
43
42
  </View>
44
43
  </View>
45
44
  )
46
45
  }
47
46
 
48
- const useStyles = () => {
47
+ const useStyles = ({ imageOnly }: { imageOnly: boolean }) => {
49
48
  const { colors } = useTheme()
50
49
 
51
50
  return StyleSheet.create({
@@ -62,31 +61,25 @@ const useStyles = () => {
62
61
  fontWeight: '600',
63
62
  color: colors.textColorDefaultPrimary,
64
63
  },
65
- messageBubbleContainer: {
66
- gap: 8,
67
- },
68
64
  messageBubble: {
69
65
  backgroundColor: colors.fillColorNeutral060,
70
66
  borderRadius: 16,
71
- paddingHorizontal: 16,
72
- paddingVertical: 12,
67
+ overflow: 'hidden',
73
68
  alignSelf: 'flex-start',
74
- maxWidth: '80%',
69
+ maxWidth: imageOnly ? '40%' : '80%',
75
70
  },
76
71
  messageText: {
77
72
  fontSize: 14,
78
73
  color: colors.textColorDefaultPrimary,
79
74
  lineHeight: 20,
75
+ paddingHorizontal: 16,
76
+ paddingVertical: 12,
80
77
  },
81
78
  imagePlaceholder: {
82
79
  height: 120,
83
- backgroundColor: colors.fillColorNeutral060,
84
- borderRadius: 16,
85
80
  justifyContent: 'center',
86
81
  alignItems: 'center',
87
82
  gap: 8,
88
- maxWidth: '80%',
89
- alignSelf: 'flex-start',
90
83
  },
91
84
  placeholderIcon: {
92
85
  fontSize: 32,
@@ -0,0 +1,101 @@
1
+ import { useMutation, useQueryClient } from '@tanstack/react-query'
2
+ import { getRequestQueryKey, useApiClient } from '../../../hooks'
3
+ import { useSuspenseGet, useSuspensePaginator } from '../../../hooks'
4
+ import { ApiResource } from '../../../types'
5
+ import { GroupMembership, GroupResourceWithMembership } from '../../../types/resources'
6
+ import { throwResponseError } from '../../../utils/response_error'
7
+
8
+ export const getGroupsRequestArgs = () => ({
9
+ url: '/me/groups',
10
+ data: {
11
+ perPage: 100,
12
+ include: ['my_group_membership'],
13
+ filter: 'user_settable_notification_level',
14
+ fields: {
15
+ Group: [],
16
+ GroupMembership: ['notification_level', 'notification_level_description'],
17
+ },
18
+ order: 'name',
19
+ },
20
+ })
21
+
22
+ export const getGroupRequestArgs = ({ groupId }: { groupId: number | string }) => ({
23
+ url: `/me/groups/${groupId}`,
24
+ data: {
25
+ include: ['my_group_membership'],
26
+ fields: {
27
+ Group: ['name', 'source_app_name', 'source_type', 'my_group_membership'],
28
+ GroupMembership: ['notification_level', 'notification_level_description'],
29
+ },
30
+ },
31
+ })
32
+
33
+ export const useGroups = () => {
34
+ const args = getGroupsRequestArgs()
35
+
36
+ return useSuspensePaginator<GroupResourceWithMembership>(args)
37
+ }
38
+
39
+ export const useGroup = ({ groupId }: { groupId: number | string }) => {
40
+ const args = getGroupRequestArgs({ groupId })
41
+
42
+ return useSuspenseGet<GroupResourceWithMembership>(args)
43
+ }
44
+
45
+ export const useGroupMembershipUpdate = ({ groupId }: { groupId: number | string }) => {
46
+ const apiClient = useApiClient()
47
+ const queryClient = useQueryClient()
48
+ const requestArgs = getGroupRequestArgs({ groupId })
49
+ const queryKey = getRequestQueryKey(requestArgs)
50
+
51
+ return useMutation({
52
+ throwOnError: true,
53
+ onMutate: notificationLevel => {
54
+ queryClient.setQueryData<ApiResource<GroupResourceWithMembership>>(queryKey, groupData => {
55
+ if (!groupData?.data.myGroupMembership) return groupData
56
+
57
+ return {
58
+ ...groupData,
59
+ data: {
60
+ ...groupData.data,
61
+ myGroupMembership: {
62
+ ...groupData.data.myGroupMembership,
63
+ notificationLevel,
64
+ },
65
+ },
66
+ }
67
+ })
68
+ },
69
+ onSuccess: response => {
70
+ queryClient.setQueryData<ApiResource<GroupResourceWithMembership>>(queryKey, groupData => {
71
+ if (!groupData?.data.myGroupMembership) return groupData
72
+
73
+ return {
74
+ ...groupData,
75
+ data: {
76
+ ...groupData.data,
77
+ myGroupMembership: {
78
+ ...groupData.data.myGroupMembership,
79
+ ...response.data,
80
+ },
81
+ },
82
+ }
83
+ })
84
+ },
85
+ mutationFn: (notificationLevel: string) => {
86
+ return apiClient.chat
87
+ .patch<ApiResource<GroupMembership>>({
88
+ url: `/me/groups/${groupId}/my_group_membership`,
89
+ data: {
90
+ data: {
91
+ type: 'GroupMembership',
92
+ attributes: {
93
+ notification_level: notificationLevel,
94
+ },
95
+ },
96
+ },
97
+ })
98
+ .catch(throwResponseError)
99
+ },
100
+ })
101
+ }