@planningcenter/chat-react-native 3.26.1-rc.0 → 3.27.0-rc.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 (23) hide show
  1. package/build/hooks/use_groups_groups.d.ts.map +1 -1
  2. package/build/hooks/use_groups_groups.js +7 -1
  3. package/build/hooks/use_groups_groups.js.map +1 -1
  4. package/build/screens/conversation_select_recipients/components/restricted_group_row.d.ts +8 -0
  5. package/build/screens/conversation_select_recipients/components/restricted_group_row.d.ts.map +1 -0
  6. package/build/screens/conversation_select_recipients/components/restricted_group_row.js +66 -0
  7. package/build/screens/conversation_select_recipients/components/restricted_group_row.js.map +1 -0
  8. package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.d.ts.map +1 -1
  9. package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.js +48 -10
  10. package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.js.map +1 -1
  11. package/build/types/resources/groups/groups_group_resource.d.ts +1 -0
  12. package/build/types/resources/groups/groups_group_resource.d.ts.map +1 -1
  13. package/build/types/resources/groups/groups_group_resource.js.map +1 -1
  14. package/package.json +2 -2
  15. package/src/hooks/use_groups_groups.ts +7 -1
  16. package/src/screens/conversation_select_recipients/components/restricted_group_row.tsx +88 -0
  17. package/src/screens/conversation_select_recipients/conversation_select_group_recipients_screen.tsx +64 -19
  18. package/src/types/resources/groups/groups_group_resource.ts +1 -0
  19. package/build/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.d.ts +0 -2
  20. package/build/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.d.ts.map +0 -1
  21. package/build/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.js +0 -17
  22. package/build/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.js.map +0 -1
  23. package/src/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.tsx +0 -21
@@ -1 +1 @@
1
- {"version":3,"file":"use_groups_groups.d.ts","sourceRoot":"","sources":["../../src/hooks/use_groups_groups.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAG9C,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY3B,CAAA;AAED,eAAO,MAAM,yBAAyB,eAGrC,CAAA"}
1
+ {"version":3,"file":"use_groups_groups.d.ts","sourceRoot":"","sources":["../../src/hooks/use_groups_groups.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAG9C,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkB3B,CAAA;AAED,eAAO,MAAM,yBAAyB,eAGrC,CAAA"}
@@ -5,7 +5,13 @@ export const useGroupsGroups = () => {
5
5
  data: {
6
6
  perPage: 100,
7
7
  fields: {
8
- Group: ['can_create_conversation', 'name', 'header_image', 'memberships_count'],
8
+ Group: [
9
+ 'can_create_conversation',
10
+ 'can_create_conversation_reason_code',
11
+ 'name',
12
+ 'header_image',
13
+ 'memberships_count',
14
+ ],
9
15
  },
10
16
  order: 'name',
11
17
  },
@@ -1 +1 @@
1
- {"version":3,"file":"use_groups_groups.js","sourceRoot":"","sources":["../../src/hooks/use_groups_groups.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAE3C,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE;IAClC,OAAO,eAAe,CAAsB;QAC1C,GAAG,EAAE,YAAY;QACjB,IAAI,EAAE;YACJ,OAAO,EAAE,GAAG;YACZ,MAAM,EAAE;gBACN,KAAK,EAAE,CAAC,yBAAyB,EAAE,MAAM,EAAE,cAAc,EAAE,mBAAmB,CAAC;aAChF;YACD,KAAK,EAAE,MAAM;SACd;QACD,GAAG,EAAE,QAAQ;KACd,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,EAAE;IAC5C,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,eAAe,EAAE,CAAA;IAC/C,OAAO,MAAM,EAAE,MAAM,GAAG,CAAC,CAAA;AAC3B,CAAC,CAAA","sourcesContent":["import { GroupsGroupResource } from '../types'\nimport { useApiPaginator } from './use_api'\n\nexport const useGroupsGroups = () => {\n return useApiPaginator<GroupsGroupResource>({\n url: '/me/groups',\n data: {\n perPage: 100,\n fields: {\n Group: ['can_create_conversation', 'name', 'header_image', 'memberships_count'],\n },\n order: 'name',\n },\n app: 'groups',\n })\n}\n\nexport const useCanDisplayGroupsGroups = () => {\n const { data: groups = [] } = useGroupsGroups()\n return groups?.length > 0\n}\n"]}
1
+ {"version":3,"file":"use_groups_groups.js","sourceRoot":"","sources":["../../src/hooks/use_groups_groups.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAE3C,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE;IAClC,OAAO,eAAe,CAAsB;QAC1C,GAAG,EAAE,YAAY;QACjB,IAAI,EAAE;YACJ,OAAO,EAAE,GAAG;YACZ,MAAM,EAAE;gBACN,KAAK,EAAE;oBACL,yBAAyB;oBACzB,qCAAqC;oBACrC,MAAM;oBACN,cAAc;oBACd,mBAAmB;iBACpB;aACF;YACD,KAAK,EAAE,MAAM;SACd;QACD,GAAG,EAAE,QAAQ;KACd,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,EAAE;IAC5C,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,eAAe,EAAE,CAAA;IAC/C,OAAO,MAAM,EAAE,MAAM,GAAG,CAAC,CAAA;AAC3B,CAAC,CAAA","sourcesContent":["import { GroupsGroupResource } from '../types'\nimport { useApiPaginator } from './use_api'\n\nexport const useGroupsGroups = () => {\n return useApiPaginator<GroupsGroupResource>({\n url: '/me/groups',\n data: {\n perPage: 100,\n fields: {\n Group: [\n 'can_create_conversation',\n 'can_create_conversation_reason_code',\n 'name',\n 'header_image',\n 'memberships_count',\n ],\n },\n order: 'name',\n },\n app: 'groups',\n })\n}\n\nexport const useCanDisplayGroupsGroups = () => {\n const { data: groups = [] } = useGroupsGroups()\n return groups?.length > 0\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { GroupsGroupResource } from '../../../types';
3
+ interface RestrictedGroupRowProps {
4
+ group: GroupsGroupResource;
5
+ }
6
+ export declare const RestrictedGroupRow: ({ group }: RestrictedGroupRowProps) => React.JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=restricted_group_row.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restricted_group_row.d.ts","sourceRoot":"","sources":["../../../../src/screens/conversation_select_recipients/components/restricted_group_row.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAGpD,UAAU,uBAAuB;IAC/B,KAAK,EAAE,mBAAmB,CAAA;CAC3B;AAaD,eAAO,MAAM,kBAAkB,cAAe,uBAAuB,sBA4BpE,CAAA"}
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import { StyleSheet, View } from 'react-native';
3
+ import { Image, Text } from '../../../components';
4
+ import { useTheme } from '../../../hooks';
5
+ import { platformFontWeightMedium } from '../../../utils';
6
+ const DEFAULT_REASON = 'Chat is not enabled for this group';
7
+ const REASON_DISPLAY_TEXT = {
8
+ leaders_only: 'Only leaders can start conversations',
9
+ chat_disabled: DEFAULT_REASON,
10
+ };
11
+ function reasonText(reasonCode) {
12
+ if (!reasonCode)
13
+ return DEFAULT_REASON;
14
+ return REASON_DISPLAY_TEXT[reasonCode] || DEFAULT_REASON;
15
+ }
16
+ export const RestrictedGroupRow = ({ group }) => {
17
+ const styles = useStyles();
18
+ return (<View style={styles.row} accessibilityLabel={`${group.name} — ${reasonText(group.canCreateConversationReasonCode)}`}>
19
+ <View style={styles.innerContainer}>
20
+ {group.headerImage?.thumbnail && (<Image source={{ uri: group.headerImage.thumbnail }} resizeMode="cover" style={styles.image} alt=""/>)}
21
+ <View style={styles.content}>
22
+ <Text style={styles.title} numberOfLines={2}>
23
+ {group.name}
24
+ </Text>
25
+ <Text variant="tertiary" numberOfLines={1}>
26
+ {reasonText(group.canCreateConversationReasonCode)}
27
+ </Text>
28
+ </View>
29
+ </View>
30
+ </View>);
31
+ };
32
+ const ASPECT_RATIO = 16 / 9;
33
+ const THUMBNAIL_WIDTH = 80;
34
+ const THUMBNAIL_HEIGHT = THUMBNAIL_WIDTH / ASPECT_RATIO;
35
+ const useStyles = () => {
36
+ const theme = useTheme();
37
+ return StyleSheet.create({
38
+ row: {
39
+ paddingLeft: 16,
40
+ opacity: 0.5,
41
+ },
42
+ innerContainer: {
43
+ flexDirection: 'row',
44
+ alignItems: 'center',
45
+ gap: 12,
46
+ paddingVertical: 16,
47
+ paddingRight: 16,
48
+ borderBottomWidth: 1,
49
+ borderColor: theme.colors.fillColorNeutral050Base,
50
+ },
51
+ image: {
52
+ width: THUMBNAIL_WIDTH,
53
+ height: THUMBNAIL_HEIGHT,
54
+ borderRadius: 4,
55
+ },
56
+ title: {
57
+ fontWeight: platformFontWeightMedium,
58
+ flexShrink: 1,
59
+ },
60
+ content: {
61
+ flexShrink: 1,
62
+ gap: 2,
63
+ },
64
+ });
65
+ };
66
+ //# sourceMappingURL=restricted_group_row.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restricted_group_row.js","sourceRoot":"","sources":["../../../../src/screens/conversation_select_recipients/components/restricted_group_row.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { Image, Text } from '../../../components'\nimport { useTheme } from '../../../hooks'\nimport { GroupsGroupResource } from '../../../types'\nimport { platformFontWeightMedium } from '../../../utils'\n\ninterface RestrictedGroupRowProps {\n group: GroupsGroupResource\n}\n\nconst DEFAULT_REASON = 'Chat is not enabled for this group'\nconst REASON_DISPLAY_TEXT: Record<string, string> = {\n leaders_only: 'Only leaders can start conversations',\n chat_disabled: DEFAULT_REASON,\n}\n\nfunction reasonText(reasonCode: string | null): string {\n if (!reasonCode) return DEFAULT_REASON\n return REASON_DISPLAY_TEXT[reasonCode] || DEFAULT_REASON\n}\n\nexport const RestrictedGroupRow = ({ group }: RestrictedGroupRowProps) => {\n const styles = useStyles()\n\n return (\n <View\n style={styles.row}\n accessibilityLabel={`${group.name} — ${reasonText(group.canCreateConversationReasonCode)}`}\n >\n <View style={styles.innerContainer}>\n {group.headerImage?.thumbnail && (\n <Image\n source={{ uri: group.headerImage.thumbnail }}\n resizeMode=\"cover\"\n style={styles.image}\n alt=\"\"\n />\n )}\n <View style={styles.content}>\n <Text style={styles.title} numberOfLines={2}>\n {group.name}\n </Text>\n <Text variant=\"tertiary\" numberOfLines={1}>\n {reasonText(group.canCreateConversationReasonCode)}\n </Text>\n </View>\n </View>\n </View>\n )\n}\n\nconst ASPECT_RATIO = 16 / 9\nconst THUMBNAIL_WIDTH = 80\nconst THUMBNAIL_HEIGHT = THUMBNAIL_WIDTH / ASPECT_RATIO\n\nconst useStyles = () => {\n const theme = useTheme()\n\n return StyleSheet.create({\n row: {\n paddingLeft: 16,\n opacity: 0.5,\n },\n innerContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n paddingVertical: 16,\n paddingRight: 16,\n borderBottomWidth: 1,\n borderColor: theme.colors.fillColorNeutral050Base,\n },\n image: {\n width: THUMBNAIL_WIDTH,\n height: THUMBNAIL_HEIGHT,\n borderRadius: 4,\n },\n title: {\n fontWeight: platformFontWeightMedium,\n flexShrink: 1,\n },\n content: {\n flexShrink: 1,\n gap: 2,\n },\n })\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_select_group_recipients_screen.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation_select_recipients/conversation_select_group_recipients_screen.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,EAAE,uCAAuC,EAAE,MAAM,sBAAsB,CAAA;AAI9E,eAAO,MAAM,uCAAuC,eAEjD,uCAAuC,sBAwCzC,CAAA"}
1
+ {"version":3,"file":"conversation_select_group_recipients_screen.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation_select_recipients/conversation_select_group_recipients_screen.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,EAAE,uCAAuC,EAAE,MAAM,sBAAsB,CAAA;AA2B9E,eAAO,MAAM,uCAAuC,eAEjD,uCAAuC,sBAuDzC,CAAA"}
@@ -1,17 +1,37 @@
1
1
  import { useNavigation } from '@react-navigation/native';
2
+ import { partition } from 'lodash';
2
3
  import React from 'react';
3
- import { FlatList, StyleSheet, View } from 'react-native';
4
- import { Heading } from '../../components';
4
+ import { SectionList, StyleSheet, View } from 'react-native';
5
+ import { Heading, Text } from '../../components';
5
6
  import { useGroupsGroups } from '../../hooks/use_groups_groups';
6
7
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
7
- import { GroupsWithoutChatDisclaimerRow } from './components/groups_without_chat_disclaimer_row';
8
8
  import { GroupsRecipientRow } from './components/groups_recipient_row';
9
+ import { RestrictedGroupRow } from './components/restricted_group_row';
10
+ const SectionKey = {
11
+ my: 'my',
12
+ more: 'more',
13
+ };
14
+ const SECTION_CONFIG = {
15
+ [SectionKey.my]: {
16
+ title: 'My groups',
17
+ subtitle: null,
18
+ ListItemComponent: GroupsRecipientRow,
19
+ },
20
+ [SectionKey.more]: {
21
+ title: 'More groups',
22
+ subtitle: 'You can not start a new conversation in these groups',
23
+ ListItemComponent: RestrictedGroupRow,
24
+ },
25
+ };
9
26
  export const ConversationSelectGroupRecipientsScreen = ({ route, }) => {
10
27
  const styles = useStyles();
11
28
  const navigation = useNavigation();
12
29
  const { data: groups = [] } = useGroupsGroups();
13
- const groupsWithCreatePermission = groups.filter(g => g.canCreateConversation);
14
- const showGroupsDisclaimer = groups.length > groupsWithCreatePermission.length;
30
+ const [myGroups, moreGroups] = partition(groups, g => g.canCreateConversation);
31
+ const sections = [
32
+ { key: SectionKey.my, data: myGroups },
33
+ { key: SectionKey.more, data: moreGroups },
34
+ ].filter(({ data }) => data.length > 0);
15
35
  const handleNavigateToConversationNew = (group) => {
16
36
  navigation.navigate('New', {
17
37
  screen: 'ConversationNew',
@@ -22,11 +42,23 @@ export const ConversationSelectGroupRecipientsScreen = ({ route, }) => {
22
42
  },
23
43
  });
24
44
  };
25
- return (<FlatList data={groupsWithCreatePermission} keyExtractor={item => item.id.toString()} contentContainerStyle={styles.contentContainer} ListHeaderComponent={<View style={styles.sectionHeader}>
26
- <Heading variant="h3">All my groups</Heading>
27
- </View>} renderItem={({ item: group }) => {
28
- return (<GroupsRecipientRow key={group.id} group={group} onPress={handleNavigateToConversationNew}/>);
29
- }} ListFooterComponent={showGroupsDisclaimer ? <GroupsWithoutChatDisclaimerRow /> : null}/>);
45
+ return (<SectionList sections={sections} keyExtractor={item => item.id.toString()} stickySectionHeadersEnabled={false} contentContainerStyle={styles.contentContainer} renderSectionHeader={({ section }) => {
46
+ const { title, subtitle } = SECTION_CONFIG[section.key];
47
+ return (<View style={[
48
+ styles.sectionHeader,
49
+ section.key === SectionKey.more && styles.sectionHeaderSpaced,
50
+ ]}>
51
+ <View>
52
+ <Heading variant="h3">{title}</Heading>
53
+ {subtitle && (<Text variant="tertiary" style={styles.sectionSubtitle}>
54
+ {subtitle}
55
+ </Text>)}
56
+ </View>
57
+ </View>);
58
+ }} renderItem={({ item: group, section }) => {
59
+ const { ListItemComponent } = SECTION_CONFIG[section.key];
60
+ return <ListItemComponent group={group} onPress={handleNavigateToConversationNew}/>;
61
+ }}/>);
30
62
  };
31
63
  const useStyles = () => {
32
64
  const { bottom } = useSafeAreaInsets();
@@ -40,6 +72,12 @@ const useStyles = () => {
40
72
  padding: 16,
41
73
  paddingBottom: 4,
42
74
  },
75
+ sectionHeaderSpaced: {
76
+ marginTop: 16,
77
+ },
78
+ sectionSubtitle: {
79
+ marginTop: 4,
80
+ },
43
81
  });
44
82
  };
45
83
  //# sourceMappingURL=conversation_select_group_recipients_screen.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_select_group_recipients_screen.js","sourceRoot":"","sources":["../../../src/screens/conversation_select_recipients/conversation_select_group_recipients_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAE1C,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAElE,OAAO,EAAE,8BAA8B,EAAE,MAAM,iDAAiD,CAAA;AAChG,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AAEtE,MAAM,CAAC,MAAM,uCAAuC,GAAG,CAAC,EACtD,KAAK,GACmC,EAAE,EAAE;IAC5C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,eAAe,EAAE,CAAA;IAC/C,MAAM,0BAA0B,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAA;IAC9E,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,GAAG,0BAA0B,CAAC,MAAM,CAAA;IAE9E,MAAM,+BAA+B,GAAG,CAAC,KAA0B,EAAE,EAAE;QACrE,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE;YACzB,MAAM,EAAE,iBAAiB;YACzB,MAAM,EAAE;gBACN,GAAG,KAAK,CAAC,MAAM;gBACf,QAAQ,EAAE,KAAK,CAAC,EAAE;gBAClB,eAAe,EAAE,QAAQ;aAC1B;SACF,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,OAAO,CACL,CAAC,QAAQ,CACP,IAAI,CAAC,CAAC,0BAA0B,CAAC,CACjC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CACzC,qBAAqB,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAC/C,mBAAmB,CAAC,CAClB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAChC;UAAA,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAC9C;QAAA,EAAE,IAAI,CACR,CAAC,CACD,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAiC,EAAE,EAAE;YAC7D,OAAO,CACL,CAAC,kBAAkB,CACjB,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CACd,KAAK,CAAC,CAAC,KAAK,CAAC,CACb,OAAO,CAAC,CAAC,+BAA+B,CAAC,EACzC,CACH,CAAA;QACH,CAAC,CAAC,CACF,mBAAmB,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,8BAA8B,CAAC,AAAD,EAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EACtF,CACH,CAAA;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,iBAAiB,EAAE,CAAA;IAEtC,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,gBAAgB,EAAE;YAChB,aAAa,EAAE,MAAM;SACtB;QACD,aAAa,EAAE;YACb,aAAa,EAAE,KAAK;YACpB,cAAc,EAAE,eAAe;YAC/B,OAAO,EAAE,EAAE;YACX,aAAa,EAAE,CAAC;SACjB;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport React from 'react'\nimport { FlatList, StyleSheet, View } from 'react-native'\nimport { Heading } from '../../components'\nimport { GroupsGroupResource } from '../../types'\nimport { useGroupsGroups } from '../../hooks/use_groups_groups'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { ConversationSelectRecipientsScreenProps } from './types/screen_props'\nimport { GroupsWithoutChatDisclaimerRow } from './components/groups_without_chat_disclaimer_row'\nimport { GroupsRecipientRow } from './components/groups_recipient_row'\n\nexport const ConversationSelectGroupRecipientsScreen = ({\n route,\n}: ConversationSelectRecipientsScreenProps) => {\n const styles = useStyles()\n const navigation = useNavigation()\n const { data: groups = [] } = useGroupsGroups()\n const groupsWithCreatePermission = groups.filter(g => g.canCreateConversation)\n const showGroupsDisclaimer = groups.length > groupsWithCreatePermission.length\n\n const handleNavigateToConversationNew = (group: GroupsGroupResource) => {\n navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n ...route.params,\n group_id: group.id,\n source_app_name: 'Groups',\n },\n })\n }\n\n return (\n <FlatList\n data={groupsWithCreatePermission}\n keyExtractor={item => item.id.toString()}\n contentContainerStyle={styles.contentContainer}\n ListHeaderComponent={\n <View style={styles.sectionHeader}>\n <Heading variant=\"h3\">All my groups</Heading>\n </View>\n }\n renderItem={({ item: group }: { item: GroupsGroupResource }) => {\n return (\n <GroupsRecipientRow\n key={group.id}\n group={group}\n onPress={handleNavigateToConversationNew}\n />\n )\n }}\n ListFooterComponent={showGroupsDisclaimer ? <GroupsWithoutChatDisclaimerRow /> : null}\n />\n )\n}\n\nconst useStyles = () => {\n const { bottom } = useSafeAreaInsets()\n\n return StyleSheet.create({\n contentContainer: {\n paddingBottom: bottom,\n },\n sectionHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n padding: 16,\n paddingBottom: 4,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"conversation_select_group_recipients_screen.js","sourceRoot":"","sources":["../../../src/screens/conversation_select_recipients/conversation_select_group_recipients_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport { partition } from 'lodash'\nimport React from 'react'\nimport { SectionList, StyleSheet, View } from 'react-native'\nimport { Heading, Text } from '../../components'\nimport { GroupsGroupResource } from '../../types'\nimport { useGroupsGroups } from '../../hooks/use_groups_groups'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { ConversationSelectRecipientsScreenProps } from './types/screen_props'\nimport { GroupsRecipientRow } from './components/groups_recipient_row'\nimport { RestrictedGroupRow } from './components/restricted_group_row'\n\nconst SectionKey = {\n my: 'my',\n more: 'more',\n} as const\n\nconst SECTION_CONFIG = {\n [SectionKey.my]: {\n title: 'My groups',\n subtitle: null,\n ListItemComponent: GroupsRecipientRow,\n },\n [SectionKey.more]: {\n title: 'More groups',\n subtitle: 'You can not start a new conversation in these groups',\n ListItemComponent: RestrictedGroupRow,\n },\n}\n\ninterface GroupsSection {\n key: keyof typeof SectionKey\n data: GroupsGroupResource[]\n}\n\nexport const ConversationSelectGroupRecipientsScreen = ({\n route,\n}: ConversationSelectRecipientsScreenProps) => {\n const styles = useStyles()\n const navigation = useNavigation()\n const { data: groups = [] } = useGroupsGroups()\n\n const [myGroups, moreGroups] = partition(groups, g => g.canCreateConversation)\n\n const sections: GroupsSection[] = [\n { key: SectionKey.my, data: myGroups },\n { key: SectionKey.more, data: moreGroups },\n ].filter(({ data }) => data.length > 0)\n\n const handleNavigateToConversationNew = (group: GroupsGroupResource) => {\n navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n ...route.params,\n group_id: group.id,\n source_app_name: 'Groups',\n },\n })\n }\n\n return (\n <SectionList<GroupsGroupResource, GroupsSection>\n sections={sections}\n keyExtractor={item => item.id.toString()}\n stickySectionHeadersEnabled={false}\n contentContainerStyle={styles.contentContainer}\n renderSectionHeader={({ section }) => {\n const { title, subtitle } = SECTION_CONFIG[section.key]\n return (\n <View\n style={[\n styles.sectionHeader,\n section.key === SectionKey.more && styles.sectionHeaderSpaced,\n ]}\n >\n <View>\n <Heading variant=\"h3\">{title}</Heading>\n {subtitle && (\n <Text variant=\"tertiary\" style={styles.sectionSubtitle}>\n {subtitle}\n </Text>\n )}\n </View>\n </View>\n )\n }}\n renderItem={({ item: group, section }) => {\n const { ListItemComponent } = SECTION_CONFIG[section.key]\n return <ListItemComponent group={group} onPress={handleNavigateToConversationNew} />\n }}\n />\n )\n}\n\nconst useStyles = () => {\n const { bottom } = useSafeAreaInsets()\n\n return StyleSheet.create({\n contentContainer: {\n paddingBottom: bottom,\n },\n sectionHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n padding: 16,\n paddingBottom: 4,\n },\n sectionHeaderSpaced: {\n marginTop: 16,\n },\n sectionSubtitle: {\n marginTop: 4,\n },\n })\n}\n"]}
@@ -10,5 +10,6 @@ export interface GroupsGroupResource extends ResourceObject {
10
10
  name: string;
11
11
  membershipsCount: number;
12
12
  canCreateConversation: boolean;
13
+ canCreateConversationReasonCode: string | null;
13
14
  }
14
15
  //# sourceMappingURL=groups_group_resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"groups_group_resource.d.ts","sourceRoot":"","sources":["../../../../src/types/resources/groups/groups_group_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IACzD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB,EAAE,MAAM,CAAA;IACxB,qBAAqB,EAAE,OAAO,CAAA;CAC/B"}
1
+ {"version":3,"file":"groups_group_resource.d.ts","sourceRoot":"","sources":["../../../../src/types/resources/groups/groups_group_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IACzD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB,EAAE,MAAM,CAAA;IACxB,qBAAqB,EAAE,OAAO,CAAA;IAC9B,+BAA+B,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"groups_group_resource.js","sourceRoot":"","sources":["../../../../src/types/resources/groups/groups_group_resource.ts"],"names":[],"mappings":"","sourcesContent":["import { ResourceObject } from '../../api_primitives'\n\nexport interface GroupsGroupResource extends ResourceObject {\n id: number\n type: 'Group'\n headerImage: {\n thumbnail: string\n medium: string\n original: string\n }\n name: string\n membershipsCount: number\n canCreateConversation: boolean\n}\n"]}
1
+ {"version":3,"file":"groups_group_resource.js","sourceRoot":"","sources":["../../../../src/types/resources/groups/groups_group_resource.ts"],"names":[],"mappings":"","sourcesContent":["import { ResourceObject } from '../../api_primitives'\n\nexport interface GroupsGroupResource extends ResourceObject {\n id: number\n type: 'Group'\n headerImage: {\n thumbnail: string\n medium: string\n original: string\n }\n name: string\n membershipsCount: number\n canCreateConversation: boolean\n canCreateConversationReasonCode: string | null\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.26.1-rc.0",
3
+ "version": "3.27.0-rc.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": "c156833a4091ac3628566c992e7ef63c19b5c630"
61
+ "gitHead": "f78fa57e7b21a19c41972fcd0e0fcc6b99e096c5"
62
62
  }
@@ -7,7 +7,13 @@ export const useGroupsGroups = () => {
7
7
  data: {
8
8
  perPage: 100,
9
9
  fields: {
10
- Group: ['can_create_conversation', 'name', 'header_image', 'memberships_count'],
10
+ Group: [
11
+ 'can_create_conversation',
12
+ 'can_create_conversation_reason_code',
13
+ 'name',
14
+ 'header_image',
15
+ 'memberships_count',
16
+ ],
11
17
  },
12
18
  order: 'name',
13
19
  },
@@ -0,0 +1,88 @@
1
+ import React from 'react'
2
+ import { StyleSheet, View } from 'react-native'
3
+ import { Image, Text } from '../../../components'
4
+ import { useTheme } from '../../../hooks'
5
+ import { GroupsGroupResource } from '../../../types'
6
+ import { platformFontWeightMedium } from '../../../utils'
7
+
8
+ interface RestrictedGroupRowProps {
9
+ group: GroupsGroupResource
10
+ }
11
+
12
+ const DEFAULT_REASON = 'Chat is not enabled for this group'
13
+ const REASON_DISPLAY_TEXT: Record<string, string> = {
14
+ leaders_only: 'Only leaders can start conversations',
15
+ chat_disabled: DEFAULT_REASON,
16
+ }
17
+
18
+ function reasonText(reasonCode: string | null): string {
19
+ if (!reasonCode) return DEFAULT_REASON
20
+ return REASON_DISPLAY_TEXT[reasonCode] || DEFAULT_REASON
21
+ }
22
+
23
+ export const RestrictedGroupRow = ({ group }: RestrictedGroupRowProps) => {
24
+ const styles = useStyles()
25
+
26
+ return (
27
+ <View
28
+ style={styles.row}
29
+ accessibilityLabel={`${group.name} — ${reasonText(group.canCreateConversationReasonCode)}`}
30
+ >
31
+ <View style={styles.innerContainer}>
32
+ {group.headerImage?.thumbnail && (
33
+ <Image
34
+ source={{ uri: group.headerImage.thumbnail }}
35
+ resizeMode="cover"
36
+ style={styles.image}
37
+ alt=""
38
+ />
39
+ )}
40
+ <View style={styles.content}>
41
+ <Text style={styles.title} numberOfLines={2}>
42
+ {group.name}
43
+ </Text>
44
+ <Text variant="tertiary" numberOfLines={1}>
45
+ {reasonText(group.canCreateConversationReasonCode)}
46
+ </Text>
47
+ </View>
48
+ </View>
49
+ </View>
50
+ )
51
+ }
52
+
53
+ const ASPECT_RATIO = 16 / 9
54
+ const THUMBNAIL_WIDTH = 80
55
+ const THUMBNAIL_HEIGHT = THUMBNAIL_WIDTH / ASPECT_RATIO
56
+
57
+ const useStyles = () => {
58
+ const theme = useTheme()
59
+
60
+ return StyleSheet.create({
61
+ row: {
62
+ paddingLeft: 16,
63
+ opacity: 0.5,
64
+ },
65
+ innerContainer: {
66
+ flexDirection: 'row',
67
+ alignItems: 'center',
68
+ gap: 12,
69
+ paddingVertical: 16,
70
+ paddingRight: 16,
71
+ borderBottomWidth: 1,
72
+ borderColor: theme.colors.fillColorNeutral050Base,
73
+ },
74
+ image: {
75
+ width: THUMBNAIL_WIDTH,
76
+ height: THUMBNAIL_HEIGHT,
77
+ borderRadius: 4,
78
+ },
79
+ title: {
80
+ fontWeight: platformFontWeightMedium,
81
+ flexShrink: 1,
82
+ },
83
+ content: {
84
+ flexShrink: 1,
85
+ gap: 2,
86
+ },
87
+ })
88
+ }
@@ -1,13 +1,37 @@
1
1
  import { useNavigation } from '@react-navigation/native'
2
+ import { partition } from 'lodash'
2
3
  import React from 'react'
3
- import { FlatList, StyleSheet, View } from 'react-native'
4
- import { Heading } from '../../components'
4
+ import { SectionList, StyleSheet, View } from 'react-native'
5
+ import { Heading, Text } from '../../components'
5
6
  import { GroupsGroupResource } from '../../types'
6
7
  import { useGroupsGroups } from '../../hooks/use_groups_groups'
7
8
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
8
9
  import { ConversationSelectRecipientsScreenProps } from './types/screen_props'
9
- import { GroupsWithoutChatDisclaimerRow } from './components/groups_without_chat_disclaimer_row'
10
10
  import { GroupsRecipientRow } from './components/groups_recipient_row'
11
+ import { RestrictedGroupRow } from './components/restricted_group_row'
12
+
13
+ const SectionKey = {
14
+ my: 'my',
15
+ more: 'more',
16
+ } as const
17
+
18
+ const SECTION_CONFIG = {
19
+ [SectionKey.my]: {
20
+ title: 'My groups',
21
+ subtitle: null,
22
+ ListItemComponent: GroupsRecipientRow,
23
+ },
24
+ [SectionKey.more]: {
25
+ title: 'More groups',
26
+ subtitle: 'You can not start a new conversation in these groups',
27
+ ListItemComponent: RestrictedGroupRow,
28
+ },
29
+ }
30
+
31
+ interface GroupsSection {
32
+ key: keyof typeof SectionKey
33
+ data: GroupsGroupResource[]
34
+ }
11
35
 
12
36
  export const ConversationSelectGroupRecipientsScreen = ({
13
37
  route,
@@ -15,8 +39,13 @@ export const ConversationSelectGroupRecipientsScreen = ({
15
39
  const styles = useStyles()
16
40
  const navigation = useNavigation()
17
41
  const { data: groups = [] } = useGroupsGroups()
18
- const groupsWithCreatePermission = groups.filter(g => g.canCreateConversation)
19
- const showGroupsDisclaimer = groups.length > groupsWithCreatePermission.length
42
+
43
+ const [myGroups, moreGroups] = partition(groups, g => g.canCreateConversation)
44
+
45
+ const sections: GroupsSection[] = [
46
+ { key: SectionKey.my, data: myGroups },
47
+ { key: SectionKey.more, data: moreGroups },
48
+ ].filter(({ data }) => data.length > 0)
20
49
 
21
50
  const handleNavigateToConversationNew = (group: GroupsGroupResource) => {
22
51
  navigation.navigate('New', {
@@ -30,25 +59,35 @@ export const ConversationSelectGroupRecipientsScreen = ({
30
59
  }
31
60
 
32
61
  return (
33
- <FlatList
34
- data={groupsWithCreatePermission}
62
+ <SectionList<GroupsGroupResource, GroupsSection>
63
+ sections={sections}
35
64
  keyExtractor={item => item.id.toString()}
65
+ stickySectionHeadersEnabled={false}
36
66
  contentContainerStyle={styles.contentContainer}
37
- ListHeaderComponent={
38
- <View style={styles.sectionHeader}>
39
- <Heading variant="h3">All my groups</Heading>
40
- </View>
41
- }
42
- renderItem={({ item: group }: { item: GroupsGroupResource }) => {
67
+ renderSectionHeader={({ section }) => {
68
+ const { title, subtitle } = SECTION_CONFIG[section.key]
43
69
  return (
44
- <GroupsRecipientRow
45
- key={group.id}
46
- group={group}
47
- onPress={handleNavigateToConversationNew}
48
- />
70
+ <View
71
+ style={[
72
+ styles.sectionHeader,
73
+ section.key === SectionKey.more && styles.sectionHeaderSpaced,
74
+ ]}
75
+ >
76
+ <View>
77
+ <Heading variant="h3">{title}</Heading>
78
+ {subtitle && (
79
+ <Text variant="tertiary" style={styles.sectionSubtitle}>
80
+ {subtitle}
81
+ </Text>
82
+ )}
83
+ </View>
84
+ </View>
49
85
  )
50
86
  }}
51
- ListFooterComponent={showGroupsDisclaimer ? <GroupsWithoutChatDisclaimerRow /> : null}
87
+ renderItem={({ item: group, section }) => {
88
+ const { ListItemComponent } = SECTION_CONFIG[section.key]
89
+ return <ListItemComponent group={group} onPress={handleNavigateToConversationNew} />
90
+ }}
52
91
  />
53
92
  )
54
93
  }
@@ -66,5 +105,11 @@ const useStyles = () => {
66
105
  padding: 16,
67
106
  paddingBottom: 4,
68
107
  },
108
+ sectionHeaderSpaced: {
109
+ marginTop: 16,
110
+ },
111
+ sectionSubtitle: {
112
+ marginTop: 4,
113
+ },
69
114
  })
70
115
  }
@@ -11,4 +11,5 @@ export interface GroupsGroupResource extends ResourceObject {
11
11
  name: string
12
12
  membershipsCount: number
13
13
  canCreateConversation: boolean
14
+ canCreateConversationReasonCode: string | null
14
15
  }
@@ -1,2 +0,0 @@
1
- export declare const GroupsWithoutChatDisclaimerRow: () => import("react").JSX.Element;
2
- //# sourceMappingURL=groups_without_chat_disclaimer_row.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"groups_without_chat_disclaimer_row.d.ts","sourceRoot":"","sources":["../../../../src/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.tsx"],"names":[],"mappings":"AAGA,eAAO,MAAM,8BAA8B,mCAQ1C,CAAA"}
@@ -1,17 +0,0 @@
1
- import { Text } from '../../../components';
2
- import { StyleSheet } from 'react-native';
3
- export const GroupsWithoutChatDisclaimerRow = () => {
4
- const styles = useStyles();
5
- return (<Text variant="footnote" style={styles.disclaimer}>
6
- *You have additional groups without chat enabled or permissions to start a new conversation.
7
- </Text>);
8
- };
9
- const useStyles = () => {
10
- return StyleSheet.create({
11
- disclaimer: {
12
- paddingHorizontal: 16,
13
- paddingVertical: 12,
14
- },
15
- });
16
- };
17
- //# sourceMappingURL=groups_without_chat_disclaimer_row.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"groups_without_chat_disclaimer_row.js","sourceRoot":"","sources":["../../../../src/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,EAAE;IACjD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,OAAO,CACL,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAChD;;IACF,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,UAAU,EAAE;YACV,iBAAiB,EAAE,EAAE;YACrB,eAAe,EAAE,EAAE;SACpB;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { Text } from '../../../components'\nimport { StyleSheet } from 'react-native'\n\nexport const GroupsWithoutChatDisclaimerRow = () => {\n const styles = useStyles()\n\n return (\n <Text variant=\"footnote\" style={styles.disclaimer}>\n *You have additional groups without chat enabled or permissions to start a new conversation.\n </Text>\n )\n}\n\nconst useStyles = () => {\n return StyleSheet.create({\n disclaimer: {\n paddingHorizontal: 16,\n paddingVertical: 12,\n },\n })\n}\n"]}
@@ -1,21 +0,0 @@
1
- import { Text } from '../../../components'
2
- import { StyleSheet } from 'react-native'
3
-
4
- export const GroupsWithoutChatDisclaimerRow = () => {
5
- const styles = useStyles()
6
-
7
- return (
8
- <Text variant="footnote" style={styles.disclaimer}>
9
- *You have additional groups without chat enabled or permissions to start a new conversation.
10
- </Text>
11
- )
12
- }
13
-
14
- const useStyles = () => {
15
- return StyleSheet.create({
16
- disclaimer: {
17
- paddingHorizontal: 16,
18
- paddingVertical: 12,
19
- },
20
- })
21
- }