@planningcenter/chat-react-native 3.16.1 → 3.17.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.
@@ -1 +1 @@
1
- {"version":3,"file":"reply_connectors.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/reply_connectors.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAU7C,UAAU,mBAAmB;IAC3B,OAAO,EAAE,eAAe,CAAA;IACxB,mBAAmB,EAAE,MAAM,CAAA;CAC5B;AAED,wBAAgB,mBAAmB,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,mBAAmB,sCA0BxF;AAGD,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,mBAAmB,sCAwCrF"}
1
+ {"version":3,"file":"reply_connectors.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/reply_connectors.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAU7C,UAAU,mBAAmB;IAC3B,OAAO,EAAE,eAAe,CAAA;IACxB,mBAAmB,EAAE,MAAM,CAAA;CAC5B;AAED,wBAAgB,mBAAmB,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,mBAAmB,sCA0BxF;AAED,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,mBAAmB,sCAsCrF"}
@@ -9,17 +9,20 @@ export function TheirReplyConnector({ message, messageBubbleHeight }) {
9
9
  const styles = useStyles();
10
10
  if (!REPLIES_FEATURE_ENABLED)
11
11
  return null;
12
- // TODO: Need to remove, just adding this to remove the lint warning about message being unused
13
- console.log('message', message);
14
12
  const connectorMap = {
15
13
  shortTailCurve: <ShortTailCurveConnector height={messageBubbleHeight / 2}/>,
14
+ shortHeadCurve: <ShortHeadCurveConnector height={messageBubbleHeight / 2}/>,
16
15
  verticalLine: <VerticalLineConnector />,
17
16
  default: null,
18
17
  };
19
- // TODO: Currently using fake message attributes. Will need to refactor once we have the message reply logic in place.
20
18
  const getConnectorKey = () => {
21
- // TODO: if (message.previousMessageIsTheirReplyMessage && message.nextMessageIsSomeoneElseReplyMessage) return 'shortTailCurve'
22
- // TODO: if (message.isRootMessage || (message.isTheirReplyMessage && message.nextMessageIsTheirReplyMessage) || (message.isTheirReplyMessage && message.nextMessageIsSomeoneElseReplyMessage && !message.nextMessageIsMyMessage)) return 'verticalLine'
19
+ const { threadPosition, renderAuthor } = message;
20
+ if (threadPosition === 'first' && !renderAuthor)
21
+ return 'shortHeadCurve';
22
+ if (threadPosition === 'last' && !renderAuthor)
23
+ return 'shortTailCurve';
24
+ if ((threadPosition === 'first' && renderAuthor) || threadPosition === 'center')
25
+ return 'verticalLine';
23
26
  return 'default';
24
27
  };
25
28
  const ConnectorComponent = connectorMap[getConnectorKey()];
@@ -27,13 +30,10 @@ export function TheirReplyConnector({ message, messageBubbleHeight }) {
27
30
  return null;
28
31
  return <View style={styles.theirReplyConnectorContainer}>{ConnectorComponent}</View>;
29
32
  }
30
- // TODO: Refactor how we choose the correct connector once we have the logic in place
31
33
  export function MyReplyConnector({ message, messageBubbleHeight }) {
32
34
  const styles = useStyles();
33
35
  if (!REPLIES_FEATURE_ENABLED)
34
36
  return null;
35
- // TODO: Need to remove, just adding this to remove the lint warning about message being unused
36
- console.log('message', message);
37
37
  const connectorMap = {
38
38
  longTailCurve: (<LongTailCurveConnector height={messageBubbleHeight / 2} style={styles.myReplyConnectorPosition}/>),
39
39
  longHeadCurve: (<LongHeadCurveConnector height={messageBubbleHeight / 2} style={styles.myReplyConnectorPosition}/>),
@@ -41,12 +41,16 @@ export function MyReplyConnector({ message, messageBubbleHeight }) {
41
41
  swirl: <SwirlConnector style={styles.myReplyConnectorPosition}/>,
42
42
  default: null,
43
43
  };
44
- // TODO: Currently using fake message attributes. Will need to refactor once we have the message reply logic in place.
45
44
  const getConnectorKey = () => {
46
- // TODO: if (message.currentMessageIsReply && (message.nextMessageIsNotReplyMessage || message.nextMessageIsDifferentReplyRootId)) return 'longTailCurve'
47
- // TODO: if (message.currentMessageIsReplyRoot && message.nextMessageIsMyReply) return 'longHeadCurve'
48
- // TODO: if (message.currentMessageIsReply && message.nextMessageIsReply) return 'verticalLine'
49
- // TODO: if (message.currentMessageIsReply && message.previousMessageSomeoneElseReply && (message.nextMessageIsSomeoneElseReply || message.nextMessageIsMyReply)) return 'swirl'
45
+ const { threadPosition, prevIsMyReply, nextIsMyReply } = message;
46
+ if (threadPosition === 'first')
47
+ return 'longHeadCurve';
48
+ if (threadPosition === 'center' && prevIsMyReply && nextIsMyReply)
49
+ return 'verticalLine';
50
+ if (threadPosition === 'center' && (!prevIsMyReply || !nextIsMyReply))
51
+ return 'swirl';
52
+ if (threadPosition === 'last')
53
+ return 'longTailCurve';
50
54
  return 'default';
51
55
  };
52
56
  const ConnectorComponent = connectorMap[getConnectorKey()];
@@ -66,6 +70,10 @@ function LongTailCurveConnector({ height, style }) {
66
70
  const styles = useStyles();
67
71
  return <View style={[styles.longTailCurveConnector, { height }, style]}/>;
68
72
  }
73
+ function ShortHeadCurveConnector({ height }) {
74
+ const styles = useStyles();
75
+ return <View style={[styles.shortHeadCurveConnector, { marginTop: height }]}/>;
76
+ }
69
77
  function ShortTailCurveConnector({ height }) {
70
78
  const styles = useStyles();
71
79
  return <View style={[styles.shortTailCurveConnector, { height }]}/>;
@@ -121,6 +129,13 @@ const useStyles = () => {
121
129
  borderBottomWidth: CONNECTOR_BORDER_WIDTH,
122
130
  borderBottomLeftRadius: 16,
123
131
  },
132
+ shortHeadCurveConnector: {
133
+ borderColor: borderColor,
134
+ borderLeftWidth: CONNECTOR_BORDER_WIDTH,
135
+ borderTopWidth: CONNECTOR_BORDER_WIDTH,
136
+ borderTopLeftRadius: 16,
137
+ flex: 1,
138
+ },
124
139
  shortTailCurveConnector: {
125
140
  borderColor: borderColor,
126
141
  borderLeftWidth: CONNECTOR_BORDER_WIDTH,
@@ -1 +1 @@
1
- {"version":3,"file":"reply_connectors.js","sourceRoot":"","sources":["../../../src/components/conversation/reply_connectors.tsx"],"names":[],"mappings":"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","sourcesContent":["import { StyleSheet, View, ViewStyle } from 'react-native'\nimport Svg, { Path } from 'react-native-svg'\nimport { useTheme } from '../../hooks'\nimport { MessageResource } from '../../types'\nimport {\n CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH,\n} from '../../utils/styles'\nimport { REPLIES_FEATURE_ENABLED } from '../../utils'\n\nconst MY_REPLY_CONNECTOR_WIDTH = 38\nconst CONNECTOR_BORDER_WIDTH = 4\n\ninterface ReplyConnectorProps {\n message: MessageResource\n messageBubbleHeight: number\n}\n\nexport function TheirReplyConnector({ message, messageBubbleHeight }: ReplyConnectorProps) {\n const styles = useStyles()\n\n if (!REPLIES_FEATURE_ENABLED) return null\n\n // TODO: Need to remove, just adding this to remove the lint warning about message being unused\n console.log('message', message)\n\n const connectorMap: Record<string, React.ReactNode | null> = {\n shortTailCurve: <ShortTailCurveConnector height={messageBubbleHeight / 2} />,\n verticalLine: <VerticalLineConnector />,\n default: null,\n }\n\n // TODO: Currently using fake message attributes. Will need to refactor once we have the message reply logic in place.\n const getConnectorKey = () => {\n // TODO: if (message.previousMessageIsTheirReplyMessage && message.nextMessageIsSomeoneElseReplyMessage) return 'shortTailCurve'\n // TODO: if (message.isRootMessage || (message.isTheirReplyMessage && message.nextMessageIsTheirReplyMessage) || (message.isTheirReplyMessage && message.nextMessageIsSomeoneElseReplyMessage && !message.nextMessageIsMyMessage)) return 'verticalLine'\n return 'default'\n }\n\n const ConnectorComponent = connectorMap[getConnectorKey()]\n\n if (!ConnectorComponent) return null\n\n return <View style={styles.theirReplyConnectorContainer}>{ConnectorComponent}</View>\n}\n\n// TODO: Refactor how we choose the correct connector once we have the logic in place\nexport function MyReplyConnector({ message, messageBubbleHeight }: ReplyConnectorProps) {\n const styles = useStyles()\n\n if (!REPLIES_FEATURE_ENABLED) return null\n\n // TODO: Need to remove, just adding this to remove the lint warning about message being unused\n console.log('message', message)\n\n const connectorMap: Record<string, React.ReactNode | null> = {\n longTailCurve: (\n <LongTailCurveConnector\n height={messageBubbleHeight / 2}\n style={styles.myReplyConnectorPosition}\n />\n ),\n longHeadCurve: (\n <LongHeadCurveConnector\n height={messageBubbleHeight / 2}\n style={styles.myReplyConnectorPosition}\n />\n ),\n verticalLine: <VerticalLineConnector style={styles.myReplyConnectorPosition} />,\n swirl: <SwirlConnector style={styles.myReplyConnectorPosition} />,\n default: null,\n }\n\n // TODO: Currently using fake message attributes. Will need to refactor once we have the message reply logic in place.\n const getConnectorKey = () => {\n // TODO: if (message.currentMessageIsReply && (message.nextMessageIsNotReplyMessage || message.nextMessageIsDifferentReplyRootId)) return 'longTailCurve'\n // TODO: if (message.currentMessageIsReplyRoot && message.nextMessageIsMyReply) return 'longHeadCurve'\n // TODO: if (message.currentMessageIsReply && message.nextMessageIsReply) return 'verticalLine'\n // TODO: if (message.currentMessageIsReply && message.previousMessageSomeoneElseReply && (message.nextMessageIsSomeoneElseReply || message.nextMessageIsMyReply)) return 'swirl'\n return 'default'\n }\n\n const ConnectorComponent = connectorMap[getConnectorKey()]\n\n if (!ConnectorComponent) return null\n\n return <View style={styles.myReplyConnectorContainer}>{ConnectorComponent}</View>\n}\n\nfunction VerticalLineConnector({ style }: { style?: ViewStyle }) {\n const styles = useStyles()\n return <View style={[styles.verticalLineConnector, style]} />\n}\n\nfunction LongHeadCurveConnector({ height, style }: { height: number; style?: ViewStyle }) {\n const styles = useStyles()\n return <View style={[styles.longHeadCurveConnector, { height, marginTop: height }, style]} />\n}\n\nfunction LongTailCurveConnector({ height, style }: { height: number; style?: ViewStyle }) {\n const styles = useStyles()\n return <View style={[styles.longTailCurveConnector, { height }, style]} />\n}\n\nfunction ShortTailCurveConnector({ height }: { height: number }) {\n const styles = useStyles()\n return <View style={[styles.shortTailCurveConnector, { height }]} />\n}\n\nfunction SwirlConnector({ style }: { style?: ViewStyle }) {\n const styles = useStyles()\n const { colors } = useTheme()\n const borderColor = colors.borderColorDefaultBase\n\n return (\n <View style={[styles.swirlConnectorContainer, style]}>\n <View style={styles.swirlConnectorVerticalLineHead} />\n <Svg width={27} height={34} fill=\"none\">\n <Path\n stroke={borderColor}\n strokeWidth={CONNECTOR_BORDER_WIDTH}\n d=\"M2.07 34c0-6.142 1.201-12.283 3.343-17m0 0c2.305-5.075 5.699-8.5 9.857-8.5 4.86 0 8.8 3.806 8.8 8.5s-3.94 8.5-8.8 8.5c-4.158 0-7.552-3.425-9.857-8.5zm0 0C3.271 12.283 2.07 6.142 2.07 0\"\n />\n </Svg>\n <View style={styles.swirlConnectorVerticalLineTail} />\n </View>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n const borderColor = colors.borderColorDefaultBase\n\n return StyleSheet.create({\n theirReplyConnectorContainer: {\n width: '50%',\n alignSelf: 'flex-end',\n flex: 1,\n },\n myReplyConnectorContainer: {\n width: MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH,\n position: 'absolute',\n left: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n top: 0,\n bottom: 0,\n },\n myReplyConnectorPosition: {\n left: '50%',\n },\n verticalLineConnector: {\n flex: 1,\n borderLeftWidth: CONNECTOR_BORDER_WIDTH,\n borderLeftColor: borderColor,\n },\n longHeadCurveConnector: {\n width: MY_REPLY_CONNECTOR_WIDTH,\n borderColor: borderColor,\n borderLeftWidth: CONNECTOR_BORDER_WIDTH,\n borderTopWidth: CONNECTOR_BORDER_WIDTH,\n borderTopLeftRadius: 16,\n flex: 1,\n },\n longTailCurveConnector: {\n width: MY_REPLY_CONNECTOR_WIDTH,\n borderColor: borderColor,\n borderLeftWidth: CONNECTOR_BORDER_WIDTH,\n borderBottomWidth: CONNECTOR_BORDER_WIDTH,\n borderBottomLeftRadius: 16,\n },\n shortTailCurveConnector: {\n borderColor: borderColor,\n borderLeftWidth: CONNECTOR_BORDER_WIDTH,\n borderBottomWidth: CONNECTOR_BORDER_WIDTH,\n borderBottomLeftRadius: 16,\n },\n swirlConnectorContainer: {\n flex: 1,\n },\n swirlConnectorVerticalLineHead: {\n backgroundColor: borderColor,\n width: CONNECTOR_BORDER_WIDTH,\n flex: 1,\n marginBottom: -1, // Ensures there is no gap between the vertical line and the swirl connector\n },\n swirlConnectorVerticalLineTail: {\n backgroundColor: borderColor,\n width: CONNECTOR_BORDER_WIDTH,\n flex: 1,\n marginTop: -1, // Ensures there is no gap between the vertical line and the swirl connector\n },\n })\n}\n"]}
1
+ {"version":3,"file":"reply_connectors.js","sourceRoot":"","sources":["../../../src/components/conversation/reply_connectors.tsx"],"names":[],"mappings":"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","sourcesContent":["import { StyleSheet, View, ViewStyle } from 'react-native'\nimport Svg, { Path } from 'react-native-svg'\nimport { useTheme } from '../../hooks'\nimport { MessageResource } from '../../types'\nimport {\n CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH,\n} from '../../utils/styles'\nimport { REPLIES_FEATURE_ENABLED } from '../../utils'\n\nconst MY_REPLY_CONNECTOR_WIDTH = 38\nconst CONNECTOR_BORDER_WIDTH = 4\n\ninterface ReplyConnectorProps {\n message: MessageResource\n messageBubbleHeight: number\n}\n\nexport function TheirReplyConnector({ message, messageBubbleHeight }: ReplyConnectorProps) {\n const styles = useStyles()\n\n if (!REPLIES_FEATURE_ENABLED) return null\n\n const connectorMap: Record<string, React.ReactNode | null> = {\n shortTailCurve: <ShortTailCurveConnector height={messageBubbleHeight / 2} />,\n shortHeadCurve: <ShortHeadCurveConnector height={messageBubbleHeight / 2} />,\n verticalLine: <VerticalLineConnector />,\n default: null,\n }\n\n const getConnectorKey = () => {\n const { threadPosition, renderAuthor } = message\n\n if (threadPosition === 'first' && !renderAuthor) return 'shortHeadCurve'\n if (threadPosition === 'last' && !renderAuthor) return 'shortTailCurve'\n if ((threadPosition === 'first' && renderAuthor) || threadPosition === 'center')\n return 'verticalLine'\n return 'default'\n }\n\n const ConnectorComponent = connectorMap[getConnectorKey()]\n if (!ConnectorComponent) return null\n\n return <View style={styles.theirReplyConnectorContainer}>{ConnectorComponent}</View>\n}\n\nexport function MyReplyConnector({ message, messageBubbleHeight }: ReplyConnectorProps) {\n const styles = useStyles()\n\n if (!REPLIES_FEATURE_ENABLED) return null\n\n const connectorMap: Record<string, React.ReactNode | null> = {\n longTailCurve: (\n <LongTailCurveConnector\n height={messageBubbleHeight / 2}\n style={styles.myReplyConnectorPosition}\n />\n ),\n longHeadCurve: (\n <LongHeadCurveConnector\n height={messageBubbleHeight / 2}\n style={styles.myReplyConnectorPosition}\n />\n ),\n verticalLine: <VerticalLineConnector style={styles.myReplyConnectorPosition} />,\n swirl: <SwirlConnector style={styles.myReplyConnectorPosition} />,\n default: null,\n }\n\n const getConnectorKey = () => {\n const { threadPosition, prevIsMyReply, nextIsMyReply } = message\n\n if (threadPosition === 'first') return 'longHeadCurve'\n if (threadPosition === 'center' && prevIsMyReply && nextIsMyReply) return 'verticalLine'\n if (threadPosition === 'center' && (!prevIsMyReply || !nextIsMyReply)) return 'swirl'\n if (threadPosition === 'last') return 'longTailCurve'\n\n return 'default'\n }\n\n const ConnectorComponent = connectorMap[getConnectorKey()]\n if (!ConnectorComponent) return null\n\n return <View style={styles.myReplyConnectorContainer}>{ConnectorComponent}</View>\n}\n\nfunction VerticalLineConnector({ style }: { style?: ViewStyle }) {\n const styles = useStyles()\n return <View style={[styles.verticalLineConnector, style]} />\n}\n\nfunction LongHeadCurveConnector({ height, style }: { height: number; style?: ViewStyle }) {\n const styles = useStyles()\n return <View style={[styles.longHeadCurveConnector, { height, marginTop: height }, style]} />\n}\n\nfunction LongTailCurveConnector({ height, style }: { height: number; style?: ViewStyle }) {\n const styles = useStyles()\n return <View style={[styles.longTailCurveConnector, { height }, style]} />\n}\n\nfunction ShortHeadCurveConnector({ height }: { height: number }) {\n const styles = useStyles()\n return <View style={[styles.shortHeadCurveConnector, { marginTop: height }]} />\n}\n\nfunction ShortTailCurveConnector({ height }: { height: number }) {\n const styles = useStyles()\n return <View style={[styles.shortTailCurveConnector, { height }]} />\n}\n\nfunction SwirlConnector({ style }: { style?: ViewStyle }) {\n const styles = useStyles()\n const { colors } = useTheme()\n const borderColor = colors.borderColorDefaultBase\n\n return (\n <View style={[styles.swirlConnectorContainer, style]}>\n <View style={styles.swirlConnectorVerticalLineHead} />\n <Svg width={27} height={34} fill=\"none\">\n <Path\n stroke={borderColor}\n strokeWidth={CONNECTOR_BORDER_WIDTH}\n d=\"M2.07 34c0-6.142 1.201-12.283 3.343-17m0 0c2.305-5.075 5.699-8.5 9.857-8.5 4.86 0 8.8 3.806 8.8 8.5s-3.94 8.5-8.8 8.5c-4.158 0-7.552-3.425-9.857-8.5zm0 0C3.271 12.283 2.07 6.142 2.07 0\"\n />\n </Svg>\n <View style={styles.swirlConnectorVerticalLineTail} />\n </View>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n const borderColor = colors.borderColorDefaultBase\n\n return StyleSheet.create({\n theirReplyConnectorContainer: {\n width: '50%',\n alignSelf: 'flex-end',\n flex: 1,\n },\n myReplyConnectorContainer: {\n width: MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH,\n position: 'absolute',\n left: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n top: 0,\n bottom: 0,\n },\n myReplyConnectorPosition: {\n left: '50%',\n },\n verticalLineConnector: {\n flex: 1,\n borderLeftWidth: CONNECTOR_BORDER_WIDTH,\n borderLeftColor: borderColor,\n },\n longHeadCurveConnector: {\n width: MY_REPLY_CONNECTOR_WIDTH,\n borderColor: borderColor,\n borderLeftWidth: CONNECTOR_BORDER_WIDTH,\n borderTopWidth: CONNECTOR_BORDER_WIDTH,\n borderTopLeftRadius: 16,\n flex: 1,\n },\n longTailCurveConnector: {\n width: MY_REPLY_CONNECTOR_WIDTH,\n borderColor: borderColor,\n borderLeftWidth: CONNECTOR_BORDER_WIDTH,\n borderBottomWidth: CONNECTOR_BORDER_WIDTH,\n borderBottomLeftRadius: 16,\n },\n shortHeadCurveConnector: {\n borderColor: borderColor,\n borderLeftWidth: CONNECTOR_BORDER_WIDTH,\n borderTopWidth: CONNECTOR_BORDER_WIDTH,\n borderTopLeftRadius: 16,\n flex: 1,\n },\n shortTailCurveConnector: {\n borderColor: borderColor,\n borderLeftWidth: CONNECTOR_BORDER_WIDTH,\n borderBottomWidth: CONNECTOR_BORDER_WIDTH,\n borderBottomLeftRadius: 16,\n },\n swirlConnectorContainer: {\n flex: 1,\n },\n swirlConnectorVerticalLineHead: {\n backgroundColor: borderColor,\n width: CONNECTOR_BORDER_WIDTH,\n flex: 1,\n marginBottom: -1, // Ensures there is no gap between the vertical line and the swirl connector\n },\n swirlConnectorVerticalLineTail: {\n backgroundColor: borderColor,\n width: CONNECTOR_BORDER_WIDTH,\n flex: 1,\n marginTop: -1, // Ensures there is no gap between the vertical line and the swirl connector\n },\n })\n}\n"]}
@@ -22,7 +22,11 @@ export type DateSeparator = {
22
22
  id: string;
23
23
  date: string;
24
24
  };
25
- export declare const groupMessages: (ms: MessageResource[]) => (MessageResource | DateSeparator)[];
25
+ interface GroupMessagesProps {
26
+ ms: MessageResource[];
27
+ inReplyScreen?: boolean;
28
+ }
29
+ export declare const groupMessages: ({ ms, inReplyScreen }: GroupMessagesProps) => (MessageResource | DateSeparator)[];
26
30
  interface ConversationScreenTitleProps extends HeaderTitleProps {
27
31
  conversation_id: number;
28
32
  badge?: ConversationBadgeResource;
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_screen.d.ts","sourceRoot":"","sources":["../../src/screens/conversation_screen.tsx"],"names":[],"mappings":"AACA,OAAO,EAAe,gBAAgB,EAAqB,MAAM,4BAA4B,CAAA;AAC7F,OAAO,EAGL,iBAAiB,EAIlB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,KAAmD,MAAM,OAAO,CAAA;AAkBvE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAA;AAOjF,MAAM,MAAM,sBAAsB,GAAG;IACnC,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,CAAC,sBAAsB,CAAC,CAAA;AAE/E,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE,uBAAuB,qBA+HpE;AAED,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAwC/E,eAAO,MAAM,aAAa,OAAQ,eAAe,EAAE,wCAkClD,CAAA;AACD,UAAU,4BAA6B,SAAQ,gBAAgB;IAC7D,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,eAAO,MAAM,uBAAuB,0DAMjC,4BAA4B,sBAiC9B,CAAA"}
1
+ {"version":3,"file":"conversation_screen.d.ts","sourceRoot":"","sources":["../../src/screens/conversation_screen.tsx"],"names":[],"mappings":"AACA,OAAO,EAAe,gBAAgB,EAAqB,MAAM,4BAA4B,CAAA;AAC7F,OAAO,EAGL,iBAAiB,EAIlB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,KAAmD,MAAM,OAAO,CAAA;AAkBvE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAA;AAOjF,MAAM,MAAM,sBAAsB,GAAG;IACnC,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,CAAC,sBAAsB,CAAC,CAAA;AAE/E,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE,uBAAuB,qBA+HpE;AAED,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAwC/E,UAAU,kBAAkB;IAC1B,EAAE,EAAE,eAAe,EAAE,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,eAAO,MAAM,aAAa,0BAA2B,kBAAkB,wCAwDtE,CAAA;AACD,UAAU,4BAA6B,SAAQ,gBAAgB;IAC7D,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,eAAO,MAAM,uBAAuB,0DAMjC,4BAA4B,sBAiC9B,CAAA"}
@@ -35,7 +35,7 @@ export function ConversationScreen({ route }) {
35
35
  useConversationMessagesJoltEvents({ conversationId: conversation_id });
36
36
  useEnsureConversationsRouteExists();
37
37
  useMarkLatestMessageRead({ conversation, messages });
38
- const messagesWithSeparators = groupMessages(messages);
38
+ const messagesWithSeparators = groupMessages({ ms: messages, inReplyScreen: !!reply_root_id });
39
39
  const noMessages = messagesWithSeparators.length === 0;
40
40
  const { repliesDisabled, memberAbility, badges, title } = conversation;
41
41
  const canReply = memberAbility?.canReply;
@@ -131,19 +131,24 @@ const useDateSeparatorStyles = () => {
131
131
  },
132
132
  });
133
133
  };
134
- export const groupMessages = (ms) => {
134
+ export const groupMessages = ({ ms, inReplyScreen }) => {
135
135
  let enrichedMessages = [];
136
136
  let encounteredOneOfMyMessages = false;
137
137
  ms.forEach((message, i) => {
138
138
  const prevMessage = ms[i + 1];
139
139
  const nextMessage = ms[i - 1];
140
140
  const date = moment(message.createdAt).format('YYYY-MM-DD');
141
+ const inThread = message.replyRootId !== null;
142
+ const threadRoot = message.replyRootId === message.id;
143
+ const prevMessageDifferentThread = message.replyRootId !== prevMessage?.replyRootId;
144
+ const nextMessageDifferentThread = message.replyRootId !== nextMessage?.replyRootId;
141
145
  const prevMessageDifferentAuthor = message.author?.id !== prevMessage?.author?.id;
142
146
  const nextMessageDifferentAuthor = message.author?.id !== nextMessage?.author?.id;
143
147
  const prevMessageMoreThan5Minutes = prevMessage &&
144
148
  new Date(message.createdAt).getTime() - new Date(prevMessage.createdAt).getTime() > 60000 * 5;
145
149
  const nextMessageMoreThan5Minutes = nextMessage &&
146
150
  new Date(nextMessage.createdAt).getTime() - new Date(message.createdAt).getTime() > 60000 * 5;
151
+ const nextMessageIsDateSeparator = nextMessage && date !== moment(nextMessage.createdAt).format('YYYY-MM-DD');
147
152
  if (message.mine && !encounteredOneOfMyMessages) {
148
153
  encounteredOneOfMyMessages = true;
149
154
  message.myLatestInConversation = true;
@@ -154,6 +159,21 @@ export const groupMessages = (ms) => {
154
159
  message.lastInGroup = !nextMessage || nextMessageDifferentAuthor || nextMessageMoreThan5Minutes;
155
160
  message.renderAuthor =
156
161
  !message.mine && (!prevMessage || prevMessageDifferentAuthor || prevMessageMoreThan5Minutes);
162
+ message.threadPosition = null;
163
+ if (!inReplyScreen && inThread) {
164
+ message.prevIsMyReply = prevMessage?.mine;
165
+ message.nextIsMyReply = nextMessage?.mine;
166
+ const firstInThread = threadRoot;
167
+ const lastInThread = nextMessageDifferentThread || nextMessageIsDateSeparator;
168
+ if (firstInThread && lastInThread)
169
+ message.threadPosition = null; // ensures we don't render a connector for root replies that aren't immediately followed up a reply
170
+ else if (firstInThread)
171
+ message.threadPosition = 'first';
172
+ else if (lastInThread)
173
+ message.threadPosition = 'last';
174
+ else if (!prevMessageDifferentThread && !nextMessageDifferentThread)
175
+ message.threadPosition = 'center';
176
+ }
157
177
  enrichedMessages.push(message);
158
178
  if (!prevMessage || date !== moment(prevMessage.createdAt).format('YYYY-MM-DD')) {
159
179
  enrichedMessages.push({ type: 'DateSeparator', id: `day-divider-${message.id}`, date });
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_screen.js","sourceRoot":"","sources":["../../src/screens/conversation_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { date as formatDate } from '@planningcenter/datetime-fmt'\nimport { HeaderTitle, HeaderTitleProps, PlatformPressable } from '@react-navigation/elements'\nimport {\n CommonActions,\n RouteProp,\n StaticScreenProps,\n useNavigation,\n useTheme as useNavigationTheme,\n useRoute,\n} from '@react-navigation/native'\nimport moment from 'moment'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\nimport { FlatList, Platform, StyleSheet, View } from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { Badge, Icon, Text } from '../components'\nimport {\n LeaderDisabledRepliesBanner,\n MemberDisabledRepliesBanner,\n} from '../components/conversation/disabled_replies_banners'\nimport { EmptyConversationBlankState } from '../components/conversation/empty_conversation_blank_state'\nimport BlankState from '../components/primitive/blank_state_primitive'\nimport { Message } from '../components/conversation/message'\nimport { MessageForm } from '../components/conversation/message_form'\nimport { TypingIndicator } from '../components/conversation/typing_indicator'\nimport { KeyboardView } from '../components/display/keyboard_view'\nimport { useTheme } from '../hooks'\nimport { useConversation } from '../hooks/use_conversation'\nimport { useConversationMessages } from '../hooks/use_conversation_messages'\nimport { useConversationMessagesJoltEvents } from '../hooks/use_conversation_messages_jolt_events'\nimport { MessageResource } from '../types'\nimport { ConversationBadgeResource } from '../types/resources/conversation_badge'\nimport { getRelativeDateStatus } from '../utils/date'\nimport { useMarkLatestMessageRead } from '../hooks/use_mark_latest_message_read'\nimport { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL } from '../utils/styles'\nimport { useConversationJoltEvents } from '../hooks/use_conversation_jolt_events'\nimport { JumpToBottomButton } from '../components/conversation/jump_to_bottom_button'\n\nexport type ConversationRouteProps = {\n conversation_id: number\n reply_root_id?: string\n replyRootAuthor?: string\n chat_group_graph_id?: string\n clear_input?: boolean\n editing_message_id?: number | null\n title?: string\n subtitle?: string\n badge?: ConversationBadgeResource\n deleted?: boolean\n}\n\nexport type ConversationScreenProps = StaticScreenProps<ConversationRouteProps>\n\nexport function ConversationScreen({ route }: ConversationScreenProps) {\n const styles = useStyles()\n const navigation = useNavigation()\n const { conversation_id, editing_message_id, reply_root_id } = route.params\n const { data: conversation } = useConversation(route.params)\n const { messages, refetch, isRefetching, fetchNextPage } = useConversationMessages({\n conversation_id,\n reply_root_id,\n })\n useConversationJoltEvents({ conversationId: conversation_id })\n useConversationMessagesJoltEvents({ conversationId: conversation_id })\n useEnsureConversationsRouteExists()\n useMarkLatestMessageRead({ conversation, messages })\n const messagesWithSeparators = groupMessages(messages)\n const noMessages = messagesWithSeparators.length === 0\n\n const { repliesDisabled, memberAbility, badges, title } = conversation\n const canReply = memberAbility?.canReply\n const showLeaderDisabledReplyBanner = canReply && repliesDisabled\n const canDeleteNonAuthoredMessages = memberAbility?.canDeleteNonAuthoredMessages ?? false\n const currentlyEditingMessage = messages.find(m => String(m.id) === String(editing_message_id))\n\n const listRef = useRef<FlatList>(null)\n const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false)\n\n const trackScroll = (event: any) => {\n const offsetY = event.nativeEvent.contentOffset.y\n setShowJumpToBottomButton(offsetY > 200)\n }\n\n const handleReturnToBottom = useCallback(() => {\n listRef.current?.scrollToOffset({\n offset: 0,\n })\n }, [])\n\n useEffect(() => {\n if (reply_root_id) return\n\n navigation.setParams({\n title: title,\n badge: badges?.[0],\n deleted: conversation?.deleted,\n })\n }, [navigation, title, badges, conversation?.deleted, reply_root_id])\n\n if (!conversation || conversation.deleted) {\n return (\n <View style={styles.container}>\n <BlankState.Root>\n <BlankState.Imagery name=\"general.outlinedTextMessage\" />\n <BlankState.Content>\n <BlankState.Heading>This conversation has been deleted</BlankState.Heading>\n </BlankState.Content>\n <BlankState.Button\n onPress={navigation.goBack}\n title=\"Back to conversations\"\n accessibilityHint=\"Navigates back to the conversations list\"\n accessibilityRole=\"link\"\n />\n </BlankState.Root>\n </View>\n )\n }\n\n return (\n <View style={styles.container}>\n <KeyboardView>\n {noMessages ? (\n <EmptyConversationBlankState />\n ) : (\n <FlatList\n inverted\n ref={listRef}\n contentContainerStyle={styles.listContainer}\n refreshing={isRefetching}\n onRefresh={refetch}\n data={messagesWithSeparators}\n keyExtractor={item => item.id}\n onScroll={trackScroll}\n scrollEventThrottle={10}\n renderItem={({ item }) => {\n if (item.type === 'DateSeparator') {\n return <InlineDateSeparator {...item} />\n }\n\n return (\n <Message\n {...item}\n canDeleteNonAuthoredMessages={canDeleteNonAuthoredMessages}\n conversation_id={conversation_id}\n latestReadMessageSortKey={conversation?.latestReadMessageSortKey}\n inReplyScreen={!!reply_root_id}\n />\n )\n }}\n onEndReached={() => fetchNextPage()}\n ListHeaderComponent={<View style={styles.listHeader} />}\n />\n )}\n <JumpToBottomButton onPress={handleReturnToBottom} visible={showJumpToBottomButton} />\n {!noMessages && <TypingIndicator conversationId={conversation_id} />}\n {showLeaderDisabledReplyBanner && <LeaderDisabledRepliesBanner />}\n {canReply ? (\n <MessageForm.Root\n conversation={conversation}\n replyRootId={reply_root_id}\n currentlyEditingMessage={currentlyEditingMessage}\n // We use a separate key so that it remounts component when switching between new\n // and edit message. This simplifies internal state handling.\n key={\n currentlyEditingMessage\n ? `edit-message-form-${currentlyEditingMessage.id}`\n : 'new-message-form'\n }\n >\n <MessageForm.AttachmentPicker />\n <MessageForm.Commands />\n <MessageForm.TextInput />\n <MessageForm.SubmitButton />\n </MessageForm.Root>\n ) : (\n <MemberDisabledRepliesBanner />\n )}\n </KeyboardView>\n </View>\n )\n}\n\nexport type DateSeparator = { type: 'DateSeparator'; id: string; date: string }\n\nfunction InlineDateSeparator({ date }: DateSeparator) {\n const styles = useDateSeparatorStyles()\n const { isThisYear } = getRelativeDateStatus(date)\n const showYear = !isThisYear\n const dateStamp = formatDate(date, { style: 'long', year: showYear })\n\n return (\n <View style={styles.container}>\n <View style={styles.separator} />\n <Text variant=\"footnote\" style={styles.dateText}>\n {dateStamp}\n </Text>\n <View style={styles.separator} />\n </View>\n )\n}\n\nconst useDateSeparatorStyles = () => {\n const theme = useTheme()\n return StyleSheet.create({\n container: {\n alignItems: 'center',\n flexDirection: 'row',\n paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n paddingVertical: 16,\n },\n separator: {\n flex: 1,\n height: 1,\n borderTopWidth: 1,\n borderTopColor: theme.colors.borderColorDefaultBase,\n },\n dateText: {\n paddingHorizontal: 8,\n },\n })\n}\n\nexport const groupMessages = (ms: MessageResource[]) => {\n let enrichedMessages: (MessageResource | DateSeparator)[] = []\n let encounteredOneOfMyMessages = false\n\n ms.forEach((message, i) => {\n const prevMessage = ms[i + 1]\n const nextMessage = ms[i - 1]\n const date = moment(message.createdAt).format('YYYY-MM-DD')\n const prevMessageDifferentAuthor = message.author?.id !== prevMessage?.author?.id\n const nextMessageDifferentAuthor = message.author?.id !== nextMessage?.author?.id\n const prevMessageMoreThan5Minutes =\n prevMessage &&\n new Date(message.createdAt).getTime() - new Date(prevMessage.createdAt).getTime() > 60000 * 5\n const nextMessageMoreThan5Minutes =\n nextMessage &&\n new Date(nextMessage.createdAt).getTime() - new Date(message.createdAt).getTime() > 60000 * 5\n\n if (message.mine && !encounteredOneOfMyMessages) {\n encounteredOneOfMyMessages = true\n message.myLatestInConversation = true\n } else {\n message.myLatestInConversation = false\n }\n message.lastInGroup = !nextMessage || nextMessageDifferentAuthor || nextMessageMoreThan5Minutes\n message.renderAuthor =\n !message.mine && (!prevMessage || prevMessageDifferentAuthor || prevMessageMoreThan5Minutes)\n\n enrichedMessages.push(message)\n if (!prevMessage || date !== moment(prevMessage.createdAt).format('YYYY-MM-DD')) {\n enrichedMessages.push({ type: 'DateSeparator', id: `day-divider-${message.id}`, date })\n }\n })\n\n return enrichedMessages\n}\ninterface ConversationScreenTitleProps extends HeaderTitleProps {\n conversation_id: number\n badge?: ConversationBadgeResource\n deleted?: boolean\n}\n\nexport const ConversationScreenTitle = ({\n conversation_id,\n badge,\n children,\n style,\n deleted,\n}: ConversationScreenTitleProps) => {\n const styles = usePressableHeaderStyle()\n const navigation = useNavigation()\n const resourceType = badge?.pcoResourceType || ''\n const productName = badge?.appName\n const name = badge?.text || undefined\n\n return (\n <PlatformPressable\n accessibilityHint=\"Opens details about members and settings\"\n style={styles.container}\n onPress={() => {\n if (deleted) return\n\n navigation.navigate('ConversationDetails', { conversation_id })\n }}\n >\n <View style={styles.titleWrapper}>\n <HeaderTitle maxFontSizeMultiplier={1} style={style}>\n {children}\n </HeaderTitle>\n {!deleted && <Icon name=\"general.downChevron\" size={12} />}\n </View>\n <Badge\n variant=\"metaSubtle\"\n productLogoName={productName}\n label={resourceType}\n metaLabel={name}\n style={styles.badge}\n maxFontSizeMultiplier={1}\n />\n </PlatformPressable>\n )\n}\n\nconst usePressableHeaderStyle = () => {\n return StyleSheet.create({\n container: {\n alignItems: Platform.select({ android: 'flex-start', default: 'center' }),\n marginRight: Platform.select({ ios: 20, default: 16 }),\n },\n titleWrapper: {\n alignItems: 'center',\n columnGap: 4,\n flexDirection: 'row',\n flexShrink: 1,\n },\n badge: {\n alignSelf: Platform.select({ android: 'flex-start', default: 'center' }),\n marginTop: 2,\n },\n })\n}\n\nconst useStyles = () => {\n const navigationTheme = useNavigationTheme()\n const { bottom } = useSafeAreaInsets()\n\n return StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: 'center',\n backgroundColor: navigationTheme.colors.card,\n paddingBottom: bottom,\n },\n listContainer: {\n paddingVertical: 12,\n },\n listHeader: {\n // Just whitespace to provide space where the typing indicator can be\n height: 16,\n },\n })\n}\n\n/**\n * useEnsureConversationsRouteExists\n */\nconst useEnsureConversationsRouteExists = () => {\n const navigation = useNavigation()\n const { params } = useRoute<RouteProp<ConversationScreenProps['route']>>()\n\n useEffect(() => {\n const navigationState = navigation.getState()\n const routes = navigationState?.routes || []\n const conversationsRoute = routes.find(r => r.name === 'Conversations')\n\n if (conversationsRoute) return\n\n navigation.dispatch(state => {\n return CommonActions.reset({\n ...state,\n routes: [\n { name: 'Conversations', params: { chat_group_graph_id: params?.chat_group_graph_id } },\n ...routes,\n ],\n index: state.index + 1,\n })\n })\n }, [navigation, params?.chat_group_graph_id])\n}\n"]}
1
+ {"version":3,"file":"conversation_screen.js","sourceRoot":"","sources":["../../src/screens/conversation_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { date as formatDate } from '@planningcenter/datetime-fmt'\nimport { HeaderTitle, HeaderTitleProps, PlatformPressable } from '@react-navigation/elements'\nimport {\n CommonActions,\n RouteProp,\n StaticScreenProps,\n useNavigation,\n useTheme as useNavigationTheme,\n useRoute,\n} from '@react-navigation/native'\nimport moment from 'moment'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\nimport { FlatList, Platform, StyleSheet, View } from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { Badge, Icon, Text } from '../components'\nimport {\n LeaderDisabledRepliesBanner,\n MemberDisabledRepliesBanner,\n} from '../components/conversation/disabled_replies_banners'\nimport { EmptyConversationBlankState } from '../components/conversation/empty_conversation_blank_state'\nimport BlankState from '../components/primitive/blank_state_primitive'\nimport { Message } from '../components/conversation/message'\nimport { MessageForm } from '../components/conversation/message_form'\nimport { TypingIndicator } from '../components/conversation/typing_indicator'\nimport { KeyboardView } from '../components/display/keyboard_view'\nimport { useTheme } from '../hooks'\nimport { useConversation } from '../hooks/use_conversation'\nimport { useConversationMessages } from '../hooks/use_conversation_messages'\nimport { useConversationMessagesJoltEvents } from '../hooks/use_conversation_messages_jolt_events'\nimport { MessageResource } from '../types'\nimport { ConversationBadgeResource } from '../types/resources/conversation_badge'\nimport { getRelativeDateStatus } from '../utils/date'\nimport { useMarkLatestMessageRead } from '../hooks/use_mark_latest_message_read'\nimport { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL } from '../utils/styles'\nimport { useConversationJoltEvents } from '../hooks/use_conversation_jolt_events'\nimport { JumpToBottomButton } from '../components/conversation/jump_to_bottom_button'\n\nexport type ConversationRouteProps = {\n conversation_id: number\n reply_root_id?: string\n replyRootAuthor?: string\n chat_group_graph_id?: string\n clear_input?: boolean\n editing_message_id?: number | null\n title?: string\n subtitle?: string\n badge?: ConversationBadgeResource\n deleted?: boolean\n}\n\nexport type ConversationScreenProps = StaticScreenProps<ConversationRouteProps>\n\nexport function ConversationScreen({ route }: ConversationScreenProps) {\n const styles = useStyles()\n const navigation = useNavigation()\n const { conversation_id, editing_message_id, reply_root_id } = route.params\n const { data: conversation } = useConversation(route.params)\n const { messages, refetch, isRefetching, fetchNextPage } = useConversationMessages({\n conversation_id,\n reply_root_id,\n })\n useConversationJoltEvents({ conversationId: conversation_id })\n useConversationMessagesJoltEvents({ conversationId: conversation_id })\n useEnsureConversationsRouteExists()\n useMarkLatestMessageRead({ conversation, messages })\n const messagesWithSeparators = groupMessages({ ms: messages, inReplyScreen: !!reply_root_id })\n const noMessages = messagesWithSeparators.length === 0\n\n const { repliesDisabled, memberAbility, badges, title } = conversation\n const canReply = memberAbility?.canReply\n const showLeaderDisabledReplyBanner = canReply && repliesDisabled\n const canDeleteNonAuthoredMessages = memberAbility?.canDeleteNonAuthoredMessages ?? false\n const currentlyEditingMessage = messages.find(m => String(m.id) === String(editing_message_id))\n\n const listRef = useRef<FlatList>(null)\n const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false)\n\n const trackScroll = (event: any) => {\n const offsetY = event.nativeEvent.contentOffset.y\n setShowJumpToBottomButton(offsetY > 200)\n }\n\n const handleReturnToBottom = useCallback(() => {\n listRef.current?.scrollToOffset({\n offset: 0,\n })\n }, [])\n\n useEffect(() => {\n if (reply_root_id) return\n\n navigation.setParams({\n title: title,\n badge: badges?.[0],\n deleted: conversation?.deleted,\n })\n }, [navigation, title, badges, conversation?.deleted, reply_root_id])\n\n if (!conversation || conversation.deleted) {\n return (\n <View style={styles.container}>\n <BlankState.Root>\n <BlankState.Imagery name=\"general.outlinedTextMessage\" />\n <BlankState.Content>\n <BlankState.Heading>This conversation has been deleted</BlankState.Heading>\n </BlankState.Content>\n <BlankState.Button\n onPress={navigation.goBack}\n title=\"Back to conversations\"\n accessibilityHint=\"Navigates back to the conversations list\"\n accessibilityRole=\"link\"\n />\n </BlankState.Root>\n </View>\n )\n }\n\n return (\n <View style={styles.container}>\n <KeyboardView>\n {noMessages ? (\n <EmptyConversationBlankState />\n ) : (\n <FlatList\n inverted\n ref={listRef}\n contentContainerStyle={styles.listContainer}\n refreshing={isRefetching}\n onRefresh={refetch}\n data={messagesWithSeparators}\n keyExtractor={item => item.id}\n onScroll={trackScroll}\n scrollEventThrottle={10}\n renderItem={({ item }) => {\n if (item.type === 'DateSeparator') {\n return <InlineDateSeparator {...item} />\n }\n\n return (\n <Message\n {...item}\n canDeleteNonAuthoredMessages={canDeleteNonAuthoredMessages}\n conversation_id={conversation_id}\n latestReadMessageSortKey={conversation?.latestReadMessageSortKey}\n inReplyScreen={!!reply_root_id}\n />\n )\n }}\n onEndReached={() => fetchNextPage()}\n ListHeaderComponent={<View style={styles.listHeader} />}\n />\n )}\n <JumpToBottomButton onPress={handleReturnToBottom} visible={showJumpToBottomButton} />\n {!noMessages && <TypingIndicator conversationId={conversation_id} />}\n {showLeaderDisabledReplyBanner && <LeaderDisabledRepliesBanner />}\n {canReply ? (\n <MessageForm.Root\n conversation={conversation}\n replyRootId={reply_root_id}\n currentlyEditingMessage={currentlyEditingMessage}\n // We use a separate key so that it remounts component when switching between new\n // and edit message. This simplifies internal state handling.\n key={\n currentlyEditingMessage\n ? `edit-message-form-${currentlyEditingMessage.id}`\n : 'new-message-form'\n }\n >\n <MessageForm.AttachmentPicker />\n <MessageForm.Commands />\n <MessageForm.TextInput />\n <MessageForm.SubmitButton />\n </MessageForm.Root>\n ) : (\n <MemberDisabledRepliesBanner />\n )}\n </KeyboardView>\n </View>\n )\n}\n\nexport type DateSeparator = { type: 'DateSeparator'; id: string; date: string }\n\nfunction InlineDateSeparator({ date }: DateSeparator) {\n const styles = useDateSeparatorStyles()\n const { isThisYear } = getRelativeDateStatus(date)\n const showYear = !isThisYear\n const dateStamp = formatDate(date, { style: 'long', year: showYear })\n\n return (\n <View style={styles.container}>\n <View style={styles.separator} />\n <Text variant=\"footnote\" style={styles.dateText}>\n {dateStamp}\n </Text>\n <View style={styles.separator} />\n </View>\n )\n}\n\nconst useDateSeparatorStyles = () => {\n const theme = useTheme()\n return StyleSheet.create({\n container: {\n alignItems: 'center',\n flexDirection: 'row',\n paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n paddingVertical: 16,\n },\n separator: {\n flex: 1,\n height: 1,\n borderTopWidth: 1,\n borderTopColor: theme.colors.borderColorDefaultBase,\n },\n dateText: {\n paddingHorizontal: 8,\n },\n })\n}\n\ninterface GroupMessagesProps {\n ms: MessageResource[]\n inReplyScreen?: boolean\n}\n\nexport const groupMessages = ({ ms, inReplyScreen }: GroupMessagesProps) => {\n let enrichedMessages: (MessageResource | DateSeparator)[] = []\n let encounteredOneOfMyMessages = false\n\n ms.forEach((message, i) => {\n const prevMessage = ms[i + 1]\n const nextMessage = ms[i - 1]\n const date = moment(message.createdAt).format('YYYY-MM-DD')\n const inThread = message.replyRootId !== null\n const threadRoot = message.replyRootId === message.id\n const prevMessageDifferentThread = message.replyRootId !== prevMessage?.replyRootId\n const nextMessageDifferentThread = message.replyRootId !== nextMessage?.replyRootId\n const prevMessageDifferentAuthor = message.author?.id !== prevMessage?.author?.id\n const nextMessageDifferentAuthor = message.author?.id !== nextMessage?.author?.id\n const prevMessageMoreThan5Minutes =\n prevMessage &&\n new Date(message.createdAt).getTime() - new Date(prevMessage.createdAt).getTime() > 60000 * 5\n const nextMessageMoreThan5Minutes =\n nextMessage &&\n new Date(nextMessage.createdAt).getTime() - new Date(message.createdAt).getTime() > 60000 * 5\n const nextMessageIsDateSeparator =\n nextMessage && date !== moment(nextMessage.createdAt).format('YYYY-MM-DD')\n\n if (message.mine && !encounteredOneOfMyMessages) {\n encounteredOneOfMyMessages = true\n message.myLatestInConversation = true\n } else {\n message.myLatestInConversation = false\n }\n message.lastInGroup = !nextMessage || nextMessageDifferentAuthor || nextMessageMoreThan5Minutes\n message.renderAuthor =\n !message.mine && (!prevMessage || prevMessageDifferentAuthor || prevMessageMoreThan5Minutes)\n message.threadPosition = null\n\n if (!inReplyScreen && inThread) {\n message.prevIsMyReply = prevMessage?.mine\n message.nextIsMyReply = nextMessage?.mine\n\n const firstInThread = threadRoot\n const lastInThread = nextMessageDifferentThread || nextMessageIsDateSeparator\n\n if (firstInThread && lastInThread)\n message.threadPosition = null // ensures we don't render a connector for root replies that aren't immediately followed up a reply\n else if (firstInThread) message.threadPosition = 'first'\n else if (lastInThread) message.threadPosition = 'last'\n else if (!prevMessageDifferentThread && !nextMessageDifferentThread)\n message.threadPosition = 'center'\n }\n\n enrichedMessages.push(message)\n if (!prevMessage || date !== moment(prevMessage.createdAt).format('YYYY-MM-DD')) {\n enrichedMessages.push({ type: 'DateSeparator', id: `day-divider-${message.id}`, date })\n }\n })\n\n return enrichedMessages\n}\ninterface ConversationScreenTitleProps extends HeaderTitleProps {\n conversation_id: number\n badge?: ConversationBadgeResource\n deleted?: boolean\n}\n\nexport const ConversationScreenTitle = ({\n conversation_id,\n badge,\n children,\n style,\n deleted,\n}: ConversationScreenTitleProps) => {\n const styles = usePressableHeaderStyle()\n const navigation = useNavigation()\n const resourceType = badge?.pcoResourceType || ''\n const productName = badge?.appName\n const name = badge?.text || undefined\n\n return (\n <PlatformPressable\n accessibilityHint=\"Opens details about members and settings\"\n style={styles.container}\n onPress={() => {\n if (deleted) return\n\n navigation.navigate('ConversationDetails', { conversation_id })\n }}\n >\n <View style={styles.titleWrapper}>\n <HeaderTitle maxFontSizeMultiplier={1} style={style}>\n {children}\n </HeaderTitle>\n {!deleted && <Icon name=\"general.downChevron\" size={12} />}\n </View>\n <Badge\n variant=\"metaSubtle\"\n productLogoName={productName}\n label={resourceType}\n metaLabel={name}\n style={styles.badge}\n maxFontSizeMultiplier={1}\n />\n </PlatformPressable>\n )\n}\n\nconst usePressableHeaderStyle = () => {\n return StyleSheet.create({\n container: {\n alignItems: Platform.select({ android: 'flex-start', default: 'center' }),\n marginRight: Platform.select({ ios: 20, default: 16 }),\n },\n titleWrapper: {\n alignItems: 'center',\n columnGap: 4,\n flexDirection: 'row',\n flexShrink: 1,\n },\n badge: {\n alignSelf: Platform.select({ android: 'flex-start', default: 'center' }),\n marginTop: 2,\n },\n })\n}\n\nconst useStyles = () => {\n const navigationTheme = useNavigationTheme()\n const { bottom } = useSafeAreaInsets()\n\n return StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: 'center',\n backgroundColor: navigationTheme.colors.card,\n paddingBottom: bottom,\n },\n listContainer: {\n paddingVertical: 12,\n },\n listHeader: {\n // Just whitespace to provide space where the typing indicator can be\n height: 16,\n },\n })\n}\n\n/**\n * useEnsureConversationsRouteExists\n */\nconst useEnsureConversationsRouteExists = () => {\n const navigation = useNavigation()\n const { params } = useRoute<RouteProp<ConversationScreenProps['route']>>()\n\n useEffect(() => {\n const navigationState = navigation.getState()\n const routes = navigationState?.routes || []\n const conversationsRoute = routes.find(r => r.name === 'Conversations')\n\n if (conversationsRoute) return\n\n navigation.dispatch(state => {\n return CommonActions.reset({\n ...state,\n routes: [\n { name: 'Conversations', params: { chat_group_graph_id: params?.chat_group_graph_id } },\n ...routes,\n ],\n index: state.index + 1,\n })\n })\n }, [navigation, params?.chat_group_graph_id])\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { StaticScreenProps } from '@react-navigation/native';
2
2
  import React from 'react';
3
- import { GraphId } from '../../types/resources/group_resource';
4
3
  import { AppName } from '../../types/resources/app_name';
4
+ import { GraphId } from '../../types/resources/group_resource';
5
5
  export type ConversationsScreenProps = StaticScreenProps<{
6
6
  title?: string;
7
7
  chat_group_graph_id?: GraphId;
@@ -1 +1 @@
1
- {"version":3,"file":"conversations_screen.d.ts","sourceRoot":"","sources":["../../../src/screens/conversations/conversations_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAsB,MAAM,OAAO,CAAA;AAM1C,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAG9D,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAExD,MAAM,MAAM,wBAAwB,GAAG,iBAAiB,CAAC;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC,CAAC,CAAA;AAEF,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,EAAE,wBAAwB,qBAkEtE"}
1
+ {"version":3,"file":"conversations_screen.d.ts","sourceRoot":"","sources":["../../../src/screens/conversations/conversations_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAsB,MAAM,OAAO,CAAA;AAM1C,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAK9D,MAAM,MAAM,wBAAwB,GAAG,iBAAiB,CAAC;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC,CAAC,CAAA;AAEF,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,EAAE,wBAAwB,qBAyDtE"}
@@ -7,10 +7,12 @@ import { ConversationsContextProvider } from '../../contexts/conversations_conte
7
7
  import { useCanCreateConversations } from '../../hooks';
8
8
  import { destructureChatGroupGraphId, MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils';
9
9
  import { ListHeaderComponent } from './components/list_header_component';
10
+ import { useAppName } from '../../hooks/use_app_name';
10
11
  export function ConversationsScreen({ route }) {
11
12
  const navigation = useNavigation();
12
13
  const canCreateConversations = useCanCreateConversations();
13
14
  const styles = useStyles();
15
+ const appName = useAppName();
14
16
  const { chat_group_graph_id } = route.params || {};
15
17
  const { sourceAppName, sourceId } = destructureChatGroupGraphId(chat_group_graph_id);
16
18
  const handleNewConversationNavigation = () => {
@@ -48,11 +50,14 @@ export function ConversationsScreen({ route }) {
48
50
  <ConversationsContextProvider args={route.params}>
49
51
  <Conversations ListHeaderComponent={ListHeaderComponent}/>
50
52
  </ConversationsContextProvider>
51
- <ActionButton visible={canCreateConversations} title="New conversation" onPress={handleNewConversationNavigation} buttonIconNameLeft="churchCenter.signups" secondaryButton={<TextButton variant="tertiary" onPress={handleGetHelp} maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK} accessibilityShowsLargeContentViewer accessibilityLargeContentTitle="Get help">
52
- Get help
53
- </TextButton>}/>
53
+ <ActionButton visible={canCreateConversations} title="New conversation" onPress={handleNewConversationNavigation} buttonIconNameLeft="churchCenter.signups" secondaryButton={appName === 'services' ? null : <GetHelpButton onPress={handleGetHelp}/>}/>
54
54
  </View>);
55
55
  }
56
+ const GetHelpButton = ({ onPress }) => {
57
+ return (<TextButton variant="tertiary" onPress={onPress} maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK} accessibilityShowsLargeContentViewer accessibilityLargeContentTitle="Get help">
58
+ Get help
59
+ </TextButton>);
60
+ };
56
61
  const useStyles = () => {
57
62
  return StyleSheet.create({
58
63
  container: {
@@ -1 +1 @@
1
- {"version":3,"file":"conversations_screen.js","sourceRoot":"","sources":["../../../src/screens/conversations/conversations_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { StaticScreenProps, useNavigation } from '@react-navigation/native'\nimport React, { useCallback } from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { Conversations, TextButton } from '../../components'\nimport { ActionButton } from '../../components/display/action_button'\nimport { ConversationsContextProvider } from '../../contexts/conversations_context'\nimport { useCanCreateConversations } from '../../hooks'\nimport { GraphId } from '../../types/resources/group_resource'\nimport { destructureChatGroupGraphId, MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'\nimport { ListHeaderComponent } from './components/list_header_component'\nimport { AppName } from '../../types/resources/app_name'\n\nexport type ConversationsScreenProps = StaticScreenProps<{\n title?: string\n chat_group_graph_id?: GraphId\n group_source_app_name?: AppName\n}>\n\nexport function ConversationsScreen({ route }: ConversationsScreenProps) {\n const navigation = useNavigation()\n const canCreateConversations = useCanCreateConversations()\n const styles = useStyles()\n\n const { chat_group_graph_id } = route.params || {}\n const { sourceAppName, sourceId } = destructureChatGroupGraphId(chat_group_graph_id)\n\n const handleNewConversationNavigation = () => {\n if (sourceAppName === 'Services') {\n return navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n team_ids: sourceId ? [sourceId] : [],\n source_app_name: sourceAppName,\n ...route.params,\n },\n })\n }\n if (sourceAppName === 'Groups') {\n return navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n group_id: sourceId,\n source_app_name: sourceAppName,\n ...route.params,\n },\n })\n }\n\n return navigation.navigate('New', {\n screen: 'ConversationSelectRecipients',\n params: {\n ...route.params,\n },\n })\n }\n\n const handleGetHelp = useCallback(() => {\n navigation.navigate('GetHelp', { type: 'chat' })\n }, [navigation])\n\n return (\n <View style={styles.container}>\n <ConversationsContextProvider args={route.params}>\n <Conversations ListHeaderComponent={ListHeaderComponent} />\n </ConversationsContextProvider>\n <ActionButton\n visible={canCreateConversations}\n title=\"New conversation\"\n onPress={handleNewConversationNavigation}\n buttonIconNameLeft=\"churchCenter.signups\"\n secondaryButton={\n <TextButton\n variant=\"tertiary\"\n onPress={handleGetHelp}\n maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}\n accessibilityShowsLargeContentViewer\n accessibilityLargeContentTitle=\"Get help\"\n >\n Get help\n </TextButton>\n }\n />\n </View>\n )\n}\n\nconst useStyles = () => {\n return StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: 'center',\n },\n })\n}\n"]}
1
+ {"version":3,"file":"conversations_screen.js","sourceRoot":"","sources":["../../../src/screens/conversations/conversations_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { StaticScreenProps, useNavigation } from '@react-navigation/native'\nimport React, { useCallback } from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { Conversations, TextButton } from '../../components'\nimport { ActionButton } from '../../components/display/action_button'\nimport { ConversationsContextProvider } from '../../contexts/conversations_context'\nimport { useCanCreateConversations } from '../../hooks'\nimport { AppName } from '../../types/resources/app_name'\nimport { GraphId } from '../../types/resources/group_resource'\nimport { destructureChatGroupGraphId, MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'\nimport { ListHeaderComponent } from './components/list_header_component'\nimport { useAppName } from '../../hooks/use_app_name'\n\nexport type ConversationsScreenProps = StaticScreenProps<{\n title?: string\n chat_group_graph_id?: GraphId\n group_source_app_name?: AppName\n}>\n\nexport function ConversationsScreen({ route }: ConversationsScreenProps) {\n const navigation = useNavigation()\n const canCreateConversations = useCanCreateConversations()\n const styles = useStyles()\n const appName = useAppName()\n\n const { chat_group_graph_id } = route.params || {}\n const { sourceAppName, sourceId } = destructureChatGroupGraphId(chat_group_graph_id)\n\n const handleNewConversationNavigation = () => {\n if (sourceAppName === 'Services') {\n return navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n team_ids: sourceId ? [sourceId] : [],\n source_app_name: sourceAppName,\n ...route.params,\n },\n })\n }\n if (sourceAppName === 'Groups') {\n return navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n group_id: sourceId,\n source_app_name: sourceAppName,\n ...route.params,\n },\n })\n }\n\n return navigation.navigate('New', {\n screen: 'ConversationSelectRecipients',\n params: {\n ...route.params,\n },\n })\n }\n\n const handleGetHelp = useCallback(() => {\n navigation.navigate('GetHelp', { type: 'chat' })\n }, [navigation])\n\n return (\n <View style={styles.container}>\n <ConversationsContextProvider args={route.params}>\n <Conversations ListHeaderComponent={ListHeaderComponent} />\n </ConversationsContextProvider>\n <ActionButton\n visible={canCreateConversations}\n title=\"New conversation\"\n onPress={handleNewConversationNavigation}\n buttonIconNameLeft=\"churchCenter.signups\"\n secondaryButton={appName === 'services' ? null : <GetHelpButton onPress={handleGetHelp} />}\n />\n </View>\n )\n}\n\nconst GetHelpButton = ({ onPress }: { onPress: () => void }) => {\n return (\n <TextButton\n variant=\"tertiary\"\n onPress={onPress}\n maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}\n accessibilityShowsLargeContentViewer\n accessibilityLargeContentTitle=\"Get help\"\n >\n Get help\n </TextButton>\n )\n}\n\nconst useStyles = () => {\n return StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: 'center',\n },\n })\n}\n"]}
@@ -20,6 +20,9 @@ export interface MessageResource {
20
20
  renderTime?: boolean;
21
21
  myLatestInConversation?: boolean;
22
22
  lastInGroup?: boolean;
23
+ threadPosition?: 'first' | 'center' | 'last' | null;
24
+ prevIsMyReply?: boolean;
25
+ nextIsMyReply?: boolean;
23
26
  pending?: boolean;
24
27
  error?: string;
25
28
  attachmentsForCreate?: DenormalizedAttachmentResourceForCreate[];
@@ -1 +1 @@
1
- {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/types/resources/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,oCAAoC,CAAA;AACnF,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAA;AACvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE,8BAA8B,EAAE,CAAA;IAC7C,MAAM,EAAE,cAAc,CAAA;IACtB,cAAc,EAAE,qBAAqB,EAAE,CAAA;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAG3B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,WAAW,CAAC,EAAE,OAAO,CAAA;IAGrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oBAAoB,CAAC,EAAE,uCAAuC,EAAE,CAAA;CACjE"}
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/types/resources/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,oCAAoC,CAAA;AACnF,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAA;AACvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE,8BAA8B,EAAE,CAAA;IAC7C,MAAM,EAAE,cAAc,CAAA;IACtB,cAAc,EAAE,qBAAqB,EAAE,CAAA;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAG3B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,cAAc,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAA;IACnD,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,CAAC,EAAE,OAAO,CAAA;IAGvB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oBAAoB,CAAC,EAAE,uCAAuC,EAAE,CAAA;CACjE"}
@@ -1 +1 @@
1
- {"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/types/resources/message.ts"],"names":[],"mappings":"","sourcesContent":["import { DenormalizedAttachmentResource } from './denormalized_attachment_resource'\nimport { DenormalizedAttachmentResourceForCreate } from './denormalized_attachment_resource_for_create'\nimport type { PersonResource } from './person'\nimport type { ReactionCountResource } from './reaction'\n\nexport interface MessageResource {\n type: 'Message'\n id: string\n text: string | null\n html: string\n createdAt: string\n deletedAt: string | null\n textEditedAt: string | null\n mine: boolean\n attachments: DenormalizedAttachmentResource[]\n author: PersonResource\n reactionCounts: ReactionCountResource[]\n replyCount: number\n replyRootId?: string | null\n\n // Custom Local Properties we set for rendering\n renderAuthor?: boolean\n renderTime?: boolean\n myLatestInConversation?: boolean\n lastInGroup?: boolean\n\n // Properties for mutation state\n pending?: boolean // Indicates if the message is optimistically created and pending server response\n error?: string // Error message if the message failed to send\n attachmentsForCreate?: DenormalizedAttachmentResourceForCreate[]\n}\n"]}
1
+ {"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/types/resources/message.ts"],"names":[],"mappings":"","sourcesContent":["import { DenormalizedAttachmentResource } from './denormalized_attachment_resource'\nimport { DenormalizedAttachmentResourceForCreate } from './denormalized_attachment_resource_for_create'\nimport type { PersonResource } from './person'\nimport type { ReactionCountResource } from './reaction'\n\nexport interface MessageResource {\n type: 'Message'\n id: string\n text: string | null\n html: string\n createdAt: string\n deletedAt: string | null\n textEditedAt: string | null\n mine: boolean\n attachments: DenormalizedAttachmentResource[]\n author: PersonResource\n reactionCounts: ReactionCountResource[]\n replyCount: number\n replyRootId?: string | null\n\n // Custom Local Properties we set for rendering\n renderAuthor?: boolean\n renderTime?: boolean\n myLatestInConversation?: boolean\n lastInGroup?: boolean\n threadPosition?: 'first' | 'center' | 'last' | null\n prevIsMyReply?: boolean\n nextIsMyReply?: boolean\n\n // Properties for mutation state\n pending?: boolean // Indicates if the message is optimistically created and pending server response\n error?: string // Error message if the message failed to send\n attachmentsForCreate?: DenormalizedAttachmentResourceForCreate[]\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.16.1",
3
+ "version": "3.17.0-rc.0",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -56,5 +56,5 @@
56
56
  "react-native-url-polyfill": "^2.0.0",
57
57
  "typescript": "<5.6.0"
58
58
  },
59
- "gitHead": "e6a1c8c0a378a65fdf41e9f72d70766a99502012"
59
+ "gitHead": "b5fc3670444218677c0c4cbcb92ca45877d0a71a"
60
60
  }
@@ -21,38 +21,34 @@ export function TheirReplyConnector({ message, messageBubbleHeight }: ReplyConne
21
21
 
22
22
  if (!REPLIES_FEATURE_ENABLED) return null
23
23
 
24
- // TODO: Need to remove, just adding this to remove the lint warning about message being unused
25
- console.log('message', message)
26
-
27
24
  const connectorMap: Record<string, React.ReactNode | null> = {
28
25
  shortTailCurve: <ShortTailCurveConnector height={messageBubbleHeight / 2} />,
26
+ shortHeadCurve: <ShortHeadCurveConnector height={messageBubbleHeight / 2} />,
29
27
  verticalLine: <VerticalLineConnector />,
30
28
  default: null,
31
29
  }
32
30
 
33
- // TODO: Currently using fake message attributes. Will need to refactor once we have the message reply logic in place.
34
31
  const getConnectorKey = () => {
35
- // TODO: if (message.previousMessageIsTheirReplyMessage && message.nextMessageIsSomeoneElseReplyMessage) return 'shortTailCurve'
36
- // TODO: if (message.isRootMessage || (message.isTheirReplyMessage && message.nextMessageIsTheirReplyMessage) || (message.isTheirReplyMessage && message.nextMessageIsSomeoneElseReplyMessage && !message.nextMessageIsMyMessage)) return 'verticalLine'
32
+ const { threadPosition, renderAuthor } = message
33
+
34
+ if (threadPosition === 'first' && !renderAuthor) return 'shortHeadCurve'
35
+ if (threadPosition === 'last' && !renderAuthor) return 'shortTailCurve'
36
+ if ((threadPosition === 'first' && renderAuthor) || threadPosition === 'center')
37
+ return 'verticalLine'
37
38
  return 'default'
38
39
  }
39
40
 
40
41
  const ConnectorComponent = connectorMap[getConnectorKey()]
41
-
42
42
  if (!ConnectorComponent) return null
43
43
 
44
44
  return <View style={styles.theirReplyConnectorContainer}>{ConnectorComponent}</View>
45
45
  }
46
46
 
47
- // TODO: Refactor how we choose the correct connector once we have the logic in place
48
47
  export function MyReplyConnector({ message, messageBubbleHeight }: ReplyConnectorProps) {
49
48
  const styles = useStyles()
50
49
 
51
50
  if (!REPLIES_FEATURE_ENABLED) return null
52
51
 
53
- // TODO: Need to remove, just adding this to remove the lint warning about message being unused
54
- console.log('message', message)
55
-
56
52
  const connectorMap: Record<string, React.ReactNode | null> = {
57
53
  longTailCurve: (
58
54
  <LongTailCurveConnector
@@ -71,17 +67,18 @@ export function MyReplyConnector({ message, messageBubbleHeight }: ReplyConnecto
71
67
  default: null,
72
68
  }
73
69
 
74
- // TODO: Currently using fake message attributes. Will need to refactor once we have the message reply logic in place.
75
70
  const getConnectorKey = () => {
76
- // TODO: if (message.currentMessageIsReply && (message.nextMessageIsNotReplyMessage || message.nextMessageIsDifferentReplyRootId)) return 'longTailCurve'
77
- // TODO: if (message.currentMessageIsReplyRoot && message.nextMessageIsMyReply) return 'longHeadCurve'
78
- // TODO: if (message.currentMessageIsReply && message.nextMessageIsReply) return 'verticalLine'
79
- // TODO: if (message.currentMessageIsReply && message.previousMessageSomeoneElseReply && (message.nextMessageIsSomeoneElseReply || message.nextMessageIsMyReply)) return 'swirl'
71
+ const { threadPosition, prevIsMyReply, nextIsMyReply } = message
72
+
73
+ if (threadPosition === 'first') return 'longHeadCurve'
74
+ if (threadPosition === 'center' && prevIsMyReply && nextIsMyReply) return 'verticalLine'
75
+ if (threadPosition === 'center' && (!prevIsMyReply || !nextIsMyReply)) return 'swirl'
76
+ if (threadPosition === 'last') return 'longTailCurve'
77
+
80
78
  return 'default'
81
79
  }
82
80
 
83
81
  const ConnectorComponent = connectorMap[getConnectorKey()]
84
-
85
82
  if (!ConnectorComponent) return null
86
83
 
87
84
  return <View style={styles.myReplyConnectorContainer}>{ConnectorComponent}</View>
@@ -102,6 +99,11 @@ function LongTailCurveConnector({ height, style }: { height: number; style?: Vie
102
99
  return <View style={[styles.longTailCurveConnector, { height }, style]} />
103
100
  }
104
101
 
102
+ function ShortHeadCurveConnector({ height }: { height: number }) {
103
+ const styles = useStyles()
104
+ return <View style={[styles.shortHeadCurveConnector, { marginTop: height }]} />
105
+ }
106
+
105
107
  function ShortTailCurveConnector({ height }: { height: number }) {
106
108
  const styles = useStyles()
107
109
  return <View style={[styles.shortTailCurveConnector, { height }]} />
@@ -167,6 +169,13 @@ const useStyles = () => {
167
169
  borderBottomWidth: CONNECTOR_BORDER_WIDTH,
168
170
  borderBottomLeftRadius: 16,
169
171
  },
172
+ shortHeadCurveConnector: {
173
+ borderColor: borderColor,
174
+ borderLeftWidth: CONNECTOR_BORDER_WIDTH,
175
+ borderTopWidth: CONNECTOR_BORDER_WIDTH,
176
+ borderTopLeftRadius: 16,
177
+ flex: 1,
178
+ },
170
179
  shortTailCurveConnector: {
171
180
  borderColor: borderColor,
172
181
  borderLeftWidth: CONNECTOR_BORDER_WIDTH,
@@ -63,7 +63,7 @@ export function ConversationScreen({ route }: ConversationScreenProps) {
63
63
  useConversationMessagesJoltEvents({ conversationId: conversation_id })
64
64
  useEnsureConversationsRouteExists()
65
65
  useMarkLatestMessageRead({ conversation, messages })
66
- const messagesWithSeparators = groupMessages(messages)
66
+ const messagesWithSeparators = groupMessages({ ms: messages, inReplyScreen: !!reply_root_id })
67
67
  const noMessages = messagesWithSeparators.length === 0
68
68
 
69
69
  const { repliesDisabled, memberAbility, badges, title } = conversation
@@ -219,7 +219,12 @@ const useDateSeparatorStyles = () => {
219
219
  })
220
220
  }
221
221
 
222
- export const groupMessages = (ms: MessageResource[]) => {
222
+ interface GroupMessagesProps {
223
+ ms: MessageResource[]
224
+ inReplyScreen?: boolean
225
+ }
226
+
227
+ export const groupMessages = ({ ms, inReplyScreen }: GroupMessagesProps) => {
223
228
  let enrichedMessages: (MessageResource | DateSeparator)[] = []
224
229
  let encounteredOneOfMyMessages = false
225
230
 
@@ -227,6 +232,10 @@ export const groupMessages = (ms: MessageResource[]) => {
227
232
  const prevMessage = ms[i + 1]
228
233
  const nextMessage = ms[i - 1]
229
234
  const date = moment(message.createdAt).format('YYYY-MM-DD')
235
+ const inThread = message.replyRootId !== null
236
+ const threadRoot = message.replyRootId === message.id
237
+ const prevMessageDifferentThread = message.replyRootId !== prevMessage?.replyRootId
238
+ const nextMessageDifferentThread = message.replyRootId !== nextMessage?.replyRootId
230
239
  const prevMessageDifferentAuthor = message.author?.id !== prevMessage?.author?.id
231
240
  const nextMessageDifferentAuthor = message.author?.id !== nextMessage?.author?.id
232
241
  const prevMessageMoreThan5Minutes =
@@ -235,6 +244,8 @@ export const groupMessages = (ms: MessageResource[]) => {
235
244
  const nextMessageMoreThan5Minutes =
236
245
  nextMessage &&
237
246
  new Date(nextMessage.createdAt).getTime() - new Date(message.createdAt).getTime() > 60000 * 5
247
+ const nextMessageIsDateSeparator =
248
+ nextMessage && date !== moment(nextMessage.createdAt).format('YYYY-MM-DD')
238
249
 
239
250
  if (message.mine && !encounteredOneOfMyMessages) {
240
251
  encounteredOneOfMyMessages = true
@@ -245,6 +256,22 @@ export const groupMessages = (ms: MessageResource[]) => {
245
256
  message.lastInGroup = !nextMessage || nextMessageDifferentAuthor || nextMessageMoreThan5Minutes
246
257
  message.renderAuthor =
247
258
  !message.mine && (!prevMessage || prevMessageDifferentAuthor || prevMessageMoreThan5Minutes)
259
+ message.threadPosition = null
260
+
261
+ if (!inReplyScreen && inThread) {
262
+ message.prevIsMyReply = prevMessage?.mine
263
+ message.nextIsMyReply = nextMessage?.mine
264
+
265
+ const firstInThread = threadRoot
266
+ const lastInThread = nextMessageDifferentThread || nextMessageIsDateSeparator
267
+
268
+ if (firstInThread && lastInThread)
269
+ message.threadPosition = null // ensures we don't render a connector for root replies that aren't immediately followed up a reply
270
+ else if (firstInThread) message.threadPosition = 'first'
271
+ else if (lastInThread) message.threadPosition = 'last'
272
+ else if (!prevMessageDifferentThread && !nextMessageDifferentThread)
273
+ message.threadPosition = 'center'
274
+ }
248
275
 
249
276
  enrichedMessages.push(message)
250
277
  if (!prevMessage || date !== moment(prevMessage.createdAt).format('YYYY-MM-DD')) {
@@ -5,10 +5,11 @@ import { Conversations, TextButton } from '../../components'
5
5
  import { ActionButton } from '../../components/display/action_button'
6
6
  import { ConversationsContextProvider } from '../../contexts/conversations_context'
7
7
  import { useCanCreateConversations } from '../../hooks'
8
+ import { AppName } from '../../types/resources/app_name'
8
9
  import { GraphId } from '../../types/resources/group_resource'
9
10
  import { destructureChatGroupGraphId, MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'
10
11
  import { ListHeaderComponent } from './components/list_header_component'
11
- import { AppName } from '../../types/resources/app_name'
12
+ import { useAppName } from '../../hooks/use_app_name'
12
13
 
13
14
  export type ConversationsScreenProps = StaticScreenProps<{
14
15
  title?: string
@@ -20,6 +21,7 @@ export function ConversationsScreen({ route }: ConversationsScreenProps) {
20
21
  const navigation = useNavigation()
21
22
  const canCreateConversations = useCanCreateConversations()
22
23
  const styles = useStyles()
24
+ const appName = useAppName()
23
25
 
24
26
  const { chat_group_graph_id } = route.params || {}
25
27
  const { sourceAppName, sourceId } = destructureChatGroupGraphId(chat_group_graph_id)
@@ -68,22 +70,26 @@ export function ConversationsScreen({ route }: ConversationsScreenProps) {
68
70
  title="New conversation"
69
71
  onPress={handleNewConversationNavigation}
70
72
  buttonIconNameLeft="churchCenter.signups"
71
- secondaryButton={
72
- <TextButton
73
- variant="tertiary"
74
- onPress={handleGetHelp}
75
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
76
- accessibilityShowsLargeContentViewer
77
- accessibilityLargeContentTitle="Get help"
78
- >
79
- Get help
80
- </TextButton>
81
- }
73
+ secondaryButton={appName === 'services' ? null : <GetHelpButton onPress={handleGetHelp} />}
82
74
  />
83
75
  </View>
84
76
  )
85
77
  }
86
78
 
79
+ const GetHelpButton = ({ onPress }: { onPress: () => void }) => {
80
+ return (
81
+ <TextButton
82
+ variant="tertiary"
83
+ onPress={onPress}
84
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
85
+ accessibilityShowsLargeContentViewer
86
+ accessibilityLargeContentTitle="Get help"
87
+ >
88
+ Get help
89
+ </TextButton>
90
+ )
91
+ }
92
+
87
93
  const useStyles = () => {
88
94
  return StyleSheet.create({
89
95
  container: {
@@ -23,6 +23,9 @@ export interface MessageResource {
23
23
  renderTime?: boolean
24
24
  myLatestInConversation?: boolean
25
25
  lastInGroup?: boolean
26
+ threadPosition?: 'first' | 'center' | 'last' | null
27
+ prevIsMyReply?: boolean
28
+ nextIsMyReply?: boolean
26
29
 
27
30
  // Properties for mutation state
28
31
  pending?: boolean // Indicates if the message is optimistically created and pending server response