@planningcenter/chat-react-native 4.4.1-qa-staging.25 → 4.4.1-qa-staging.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/conversations/conversations.d.ts.map +1 -1
- package/build/components/conversations/conversations.js +3 -2
- package/build/components/conversations/conversations.js.map +1 -1
- package/build/components/display/filter_dropdown.d.ts +6 -1
- package/build/components/display/filter_dropdown.d.ts.map +1 -1
- package/build/components/display/filter_dropdown.js +57 -35
- package/build/components/display/filter_dropdown.js.map +1 -1
- package/build/components/display/index.d.ts +1 -0
- package/build/components/display/index.d.ts.map +1 -1
- package/build/components/display/index.js +1 -0
- package/build/components/display/index.js.map +1 -1
- package/build/components/display/popover_menu_view.d.ts +8 -0
- package/build/components/display/popover_menu_view.d.ts.map +1 -0
- package/build/components/display/popover_menu_view.js +482 -0
- package/build/components/display/popover_menu_view.js.map +1 -0
- package/build/contexts/conversations_context.d.ts.map +1 -1
- package/build/contexts/conversations_context.js +20 -17
- package/build/contexts/conversations_context.js.map +1 -1
- package/build/hooks/use_clear_conversation_filters.d.ts.map +1 -1
- package/build/hooks/use_clear_conversation_filters.js +2 -1
- package/build/hooks/use_clear_conversation_filters.js.map +1 -1
- package/build/hooks/use_conversations_cache.d.ts +1 -1
- package/build/hooks/use_conversations_cache.d.ts.map +1 -1
- package/build/hooks/use_conversations_cache.js +64 -55
- package/build/hooks/use_conversations_cache.js.map +1 -1
- package/build/hooks/use_conversations_jolt_events.js +2 -2
- package/build/hooks/use_conversations_jolt_events.js.map +1 -1
- package/build/hooks/use_jolt.d.ts.map +1 -1
- package/build/hooks/use_jolt.js +37 -9
- package/build/hooks/use_jolt.js.map +1 -1
- package/build/screens/conversation_filters/context/conversation_filter_context.d.ts.map +1 -1
- package/build/screens/conversation_filters/context/conversation_filter_context.js +8 -4
- package/build/screens/conversation_filters/context/conversation_filter_context.js.map +1 -1
- package/build/screens/conversation_filters/screen_props.d.ts +1 -0
- package/build/screens/conversation_filters/screen_props.d.ts.map +1 -1
- package/build/screens/conversation_filters/screen_props.js.map +1 -1
- package/build/screens/conversations/components/filter_dropdown_list_header_component.d.ts.map +1 -1
- package/build/screens/conversations/components/filter_dropdown_list_header_component.js +251 -185
- package/build/screens/conversations/components/filter_dropdown_list_header_component.js.map +1 -1
- package/build/screens/conversations/conversations_screen.d.ts +1 -0
- package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
- package/build/screens/conversations/conversations_screen.js +1 -2
- package/build/screens/conversations/conversations_screen.js.map +1 -1
- package/build/screens/design_system_screen.d.ts.map +1 -1
- package/build/screens/design_system_screen.js +289 -201
- package/build/screens/design_system_screen.js.map +1 -1
- package/build/utils/native_adapters/menu.d.ts +1 -2
- package/build/utils/native_adapters/menu.d.ts.map +1 -1
- package/build/utils/native_adapters/menu.js +2 -41
- package/build/utils/native_adapters/menu.js.map +1 -1
- package/build/utils/request/conversation.d.ts +2 -1
- package/build/utils/request/conversation.d.ts.map +1 -1
- package/build/utils/request/conversation.js +4 -1
- package/build/utils/request/conversation.js.map +1 -1
- package/package.json +3 -3
- package/src/components/conversations/__tests__/conversations_blank_state.test.tsx +1 -0
- package/src/components/conversations/conversations.tsx +12 -2
- package/src/components/display/__tests__/filter_dropdown.test.tsx +18 -2
- package/src/components/display/__tests__/popover_menu_view.test.tsx +63 -0
- package/src/components/display/filter_dropdown.tsx +11 -3
- package/src/components/display/index.ts +1 -0
- package/src/components/display/popover_menu_view.tsx +239 -0
- package/src/contexts/conversations_context.tsx +8 -1
- package/src/hooks/__tests__/use_conversations_jolt_events.test.tsx +135 -0
- package/src/hooks/__tests__/use_jolt.test.tsx +76 -1
- package/src/hooks/use_clear_conversation_filters.ts +1 -0
- package/src/hooks/use_conversations_cache.ts +29 -24
- package/src/hooks/use_conversations_jolt_events.ts +2 -2
- package/src/hooks/use_jolt.ts +26 -2
- package/src/screens/conversation_filters/context/conversation_filter_context.tsx +4 -0
- package/src/screens/conversation_filters/screen_props.ts +1 -0
- package/src/screens/conversations/__tests__/conversations_screen.test.tsx +2 -12
- package/src/screens/conversations/components/__tests__/filter_dropdown_list_header_component.test.tsx +74 -7
- package/src/screens/conversations/components/filter_dropdown_list_header_component.tsx +55 -14
- package/src/screens/conversations/conversations_screen.tsx +2 -2
- package/src/screens/design_system_screen.tsx +34 -1
- package/src/utils/__tests__/conversation.test.ts +1 -0
- package/src/utils/native_adapters/menu.tsx +4 -18
- package/src/utils/request/conversation.ts +4 -0
- package/src/utils/native_adapters/__tests__/menu.test.tsx +0 -46
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../../../src/utils/native_adapters/menu.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../../../src/utils/native_adapters/menu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AASnD,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,KAAK,CAAA;AAE1C,MAAM,WAAW,oBAAoB;IACnC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC,UAAU,CAAC,EAAE,UAAU,EAAE,CAAA;IACzB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,UAAU,EAAE,CAAA;IACrB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAA;IAChD,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAED,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,CAAA;AAMzD,qBAAa,WAAW;IACtB,IAAI,CAAC,EAAE,QAAQ,CAAA;gBAEH,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAA;KAAE;CAGzC"}
|
|
@@ -1,56 +1,17 @@
|
|
|
1
|
-
import { c as _c } from "react/compiler-runtime";
|
|
2
|
-
import React, { useEffect } from 'react';
|
|
3
|
-
import { View } from 'react-native';
|
|
4
|
-
|
|
5
1
|
// =================================
|
|
6
2
|
// ====== Types ====================
|
|
7
3
|
// =================================
|
|
8
4
|
|
|
9
5
|
// Mirrors the props shared by `@expo/ui/community/menu` and
|
|
10
6
|
// `@react-native-menu/menu`, so a host can pass either `MenuView` straight in.
|
|
11
|
-
|
|
7
|
+
|
|
12
8
|
// =================================
|
|
13
9
|
// ====== Adapter ==================
|
|
14
10
|
// =================================
|
|
15
11
|
|
|
16
|
-
function UnconfiguredMenuView(t0) {
|
|
17
|
-
const $ = _c(5);
|
|
18
|
-
const {
|
|
19
|
-
children,
|
|
20
|
-
style,
|
|
21
|
-
testID
|
|
22
|
-
} = t0;
|
|
23
|
-
let t1;
|
|
24
|
-
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
25
|
-
t1 = [];
|
|
26
|
-
$[0] = t1;
|
|
27
|
-
} else {
|
|
28
|
-
t1 = $[0];
|
|
29
|
-
}
|
|
30
|
-
useEffect(_temp, t1);
|
|
31
|
-
let t2;
|
|
32
|
-
if ($[1] !== children || $[2] !== style || $[3] !== testID) {
|
|
33
|
-
t2 = /*#__PURE__*/_jsx(View, {
|
|
34
|
-
style: style,
|
|
35
|
-
testID: testID,
|
|
36
|
-
children: children
|
|
37
|
-
});
|
|
38
|
-
$[1] = children;
|
|
39
|
-
$[2] = style;
|
|
40
|
-
$[3] = testID;
|
|
41
|
-
$[4] = t2;
|
|
42
|
-
} else {
|
|
43
|
-
t2 = $[4];
|
|
44
|
-
}
|
|
45
|
-
return t2;
|
|
46
|
-
}
|
|
47
|
-
function _temp() {
|
|
48
|
-
console.warn("ChatAdapters.configure() must include a menu adapter before rendering a menu");
|
|
49
|
-
}
|
|
50
12
|
export class MenuAdapter {
|
|
51
13
|
constructor(methods) {
|
|
52
|
-
this.View = methods?.View
|
|
53
|
-
this.isConfigured = !!methods?.View;
|
|
14
|
+
this.View = methods?.View;
|
|
54
15
|
}
|
|
55
16
|
}
|
|
56
17
|
//# sourceMappingURL=menu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu.js","names":["
|
|
1
|
+
{"version":3,"file":"menu.js","names":["MenuAdapter","constructor","methods","View"],"sources":["../../../src/utils/native_adapters/menu.tsx"],"sourcesContent":["import React from 'react'\nimport { StyleProp, ViewStyle } from 'react-native'\n\n// =================================\n// ====== Types ====================\n// =================================\n\n// Mirrors the props shared by `@expo/ui/community/menu` and\n// `@react-native-menu/menu`, so a host can pass either `MenuView` straight in.\n\nexport type MenuActionState = 'on' | 'off'\n\nexport interface MenuActionAttributes {\n destructive?: boolean\n disabled?: boolean\n hidden?: boolean\n}\n\nexport interface MenuAction {\n id?: string\n title: string\n state?: MenuActionState\n attributes?: MenuActionAttributes\n subactions?: MenuAction[]\n displayInline?: boolean\n}\n\nexport interface MenuActionEvent {\n nativeEvent: { event: string }\n}\n\nexport interface MenuViewProps {\n actions: MenuAction[]\n onPressAction?: (event: MenuActionEvent) => void\n onOpenMenu?: () => void\n onCloseMenu?: () => void\n shouldOpenOnLongPress?: boolean\n title?: string\n style?: StyleProp<ViewStyle>\n testID?: string\n children?: React.ReactNode\n}\n\nexport type MenuView = React.ComponentType<MenuViewProps>\n\n// =================================\n// ====== Adapter ==================\n// =================================\n\nexport class MenuAdapter {\n View?: MenuView\n\n constructor(methods?: { View: MenuView }) {\n this.View = methods?.View\n }\n}\n"],"mappings":"AAGA;AACA;AACA;;AAEA;AACA;;AAqCA;AACA;AACA;;AAEA,OAAO,MAAMA,WAAW,CAAC;EAGvBC,WAAWA,CAACC,OAA4B,EAAE;IACxC,IAAI,CAACC,IAAI,GAAGD,OAAO,EAAEC,IAAI;EAC3B;AACF","ignoreList":[]}
|
|
@@ -6,6 +6,7 @@ export interface ConversationRequestArgs {
|
|
|
6
6
|
group_source_app_name?: string;
|
|
7
7
|
show_direct_messages?: boolean;
|
|
8
8
|
show_archived?: boolean;
|
|
9
|
+
show_unread?: boolean;
|
|
9
10
|
}
|
|
10
|
-
export declare const getConversationsRequestArgs: ({ gids, chat_group_graph_id, group_source_app_name, show_direct_messages, show_archived, }?: Partial<ConversationRequestArgs>) => GetRequest;
|
|
11
|
+
export declare const getConversationsRequestArgs: ({ gids, chat_group_graph_id, group_source_app_name, show_direct_messages, show_archived, show_unread, }?: Partial<ConversationRequestArgs>) => GetRequest;
|
|
11
12
|
//# sourceMappingURL=conversation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/utils/request/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/utils/request/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,eAAO,MAAM,2BAA2B,GAAI,0GAOzC,OAAO,CAAC,uBAAuB,CAAM,KAAG,UAyD1C,CAAA"}
|
|
@@ -3,13 +3,16 @@ export const getConversationsRequestArgs = ({
|
|
|
3
3
|
chat_group_graph_id,
|
|
4
4
|
group_source_app_name,
|
|
5
5
|
show_direct_messages,
|
|
6
|
-
show_archived
|
|
6
|
+
show_archived,
|
|
7
|
+
show_unread
|
|
7
8
|
} = {}) => {
|
|
8
9
|
let filter;
|
|
9
10
|
if (chat_group_graph_id) {
|
|
10
11
|
filter = 'mine_or_not_empty,group';
|
|
11
12
|
} else if (show_archived) {
|
|
12
13
|
filter = 'mine_or_not_empty,archived';
|
|
14
|
+
} else if (show_unread) {
|
|
15
|
+
filter = 'mine_or_not_empty,unread';
|
|
13
16
|
} else if (show_direct_messages) {
|
|
14
17
|
filter = 'mine_or_not_empty,direct_message';
|
|
15
18
|
} else if (group_source_app_name) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.js","names":["getConversationsRequestArgs","gids","chat_group_graph_id","group_source_app_name","show_direct_messages","show_archived","filter","url","data","perPage","order","group","fields","Conversation","AnalyticsMetadata","ConversationBadge","include"],"sources":["../../../src/utils/request/conversation.ts"],"sourcesContent":["import { GraphId } from '../../types/resources/group_resource'\nimport { GetRequest } from '../client/types'\n\nexport interface ConversationRequestArgs {\n gids: string\n chat_group_graph_id?: GraphId\n group_source_app_name?: string\n show_direct_messages?: boolean\n show_archived?: boolean\n}\n\nexport const getConversationsRequestArgs = ({\n gids,\n chat_group_graph_id,\n group_source_app_name,\n show_direct_messages,\n show_archived,\n}: Partial<ConversationRequestArgs> = {}): GetRequest => {\n let filter: string\n if (chat_group_graph_id) {\n filter = 'mine_or_not_empty,group'\n } else if (show_archived) {\n filter = 'mine_or_not_empty,archived'\n } else if (show_direct_messages) {\n filter = 'mine_or_not_empty,direct_message'\n } else if (group_source_app_name) {\n filter = 'mine_or_not_empty,group_source_app_name'\n } else {\n filter = 'mine_or_not_empty'\n }\n\n return {\n url: '/me/conversations',\n data: {\n perPage: 20,\n order: '-last_message',\n filter,\n gids,\n group: chat_group_graph_id,\n group_source_app_name,\n fields: {\n Conversation: [\n 'created_at',\n 'badges',\n 'conversation_preview',\n 'disabled',\n 'disabled_reason',\n 'disabled_message',\n 'groups',\n 'last_message_author_id',\n 'last_message_author_name',\n 'last_message_created_at',\n 'last_message_text_preview',\n 'preview_avatar_urls',\n 'custom_avatar_type',\n 'custom_avatar_key',\n 'custom_avatar_color',\n 'custom_avatar_image_url',\n 'member_ability',\n 'muted',\n 'replies_disabled',\n 'title',\n 'unread_count',\n 'unread_reaction',\n 'updated_at',\n ],\n AnalyticsMetadata: ['metadata'],\n ConversationBadge: ['app_name', 'pco_resource_type', 'text'],\n },\n include: ['badges', 'analytics_metadata'],\n },\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"conversation.js","names":["getConversationsRequestArgs","gids","chat_group_graph_id","group_source_app_name","show_direct_messages","show_archived","show_unread","filter","url","data","perPage","order","group","fields","Conversation","AnalyticsMetadata","ConversationBadge","include"],"sources":["../../../src/utils/request/conversation.ts"],"sourcesContent":["import { GraphId } from '../../types/resources/group_resource'\nimport { GetRequest } from '../client/types'\n\nexport interface ConversationRequestArgs {\n gids: string\n chat_group_graph_id?: GraphId\n group_source_app_name?: string\n show_direct_messages?: boolean\n show_archived?: boolean\n show_unread?: boolean\n}\n\nexport const getConversationsRequestArgs = ({\n gids,\n chat_group_graph_id,\n group_source_app_name,\n show_direct_messages,\n show_archived,\n show_unread,\n}: Partial<ConversationRequestArgs> = {}): GetRequest => {\n let filter: string\n if (chat_group_graph_id) {\n filter = 'mine_or_not_empty,group'\n } else if (show_archived) {\n filter = 'mine_or_not_empty,archived'\n } else if (show_unread) {\n filter = 'mine_or_not_empty,unread'\n } else if (show_direct_messages) {\n filter = 'mine_or_not_empty,direct_message'\n } else if (group_source_app_name) {\n filter = 'mine_or_not_empty,group_source_app_name'\n } else {\n filter = 'mine_or_not_empty'\n }\n\n return {\n url: '/me/conversations',\n data: {\n perPage: 20,\n order: '-last_message',\n filter,\n gids,\n group: chat_group_graph_id,\n group_source_app_name,\n fields: {\n Conversation: [\n 'created_at',\n 'badges',\n 'conversation_preview',\n 'disabled',\n 'disabled_reason',\n 'disabled_message',\n 'groups',\n 'last_message_author_id',\n 'last_message_author_name',\n 'last_message_created_at',\n 'last_message_text_preview',\n 'preview_avatar_urls',\n 'custom_avatar_type',\n 'custom_avatar_key',\n 'custom_avatar_color',\n 'custom_avatar_image_url',\n 'member_ability',\n 'muted',\n 'replies_disabled',\n 'title',\n 'unread_count',\n 'unread_reaction',\n 'updated_at',\n ],\n AnalyticsMetadata: ['metadata'],\n ConversationBadge: ['app_name', 'pco_resource_type', 'text'],\n },\n include: ['badges', 'analytics_metadata'],\n },\n }\n}\n"],"mappings":"AAYA,OAAO,MAAMA,2BAA2B,GAAGA,CAAC;EAC1CC,IAAI;EACJC,mBAAmB;EACnBC,qBAAqB;EACrBC,oBAAoB;EACpBC,aAAa;EACbC;AACgC,CAAC,GAAG,CAAC,CAAC,KAAiB;EACvD,IAAIC,MAAc;EAClB,IAAIL,mBAAmB,EAAE;IACvBK,MAAM,GAAG,yBAAyB;EACpC,CAAC,MAAM,IAAIF,aAAa,EAAE;IACxBE,MAAM,GAAG,4BAA4B;EACvC,CAAC,MAAM,IAAID,WAAW,EAAE;IACtBC,MAAM,GAAG,0BAA0B;EACrC,CAAC,MAAM,IAAIH,oBAAoB,EAAE;IAC/BG,MAAM,GAAG,kCAAkC;EAC7C,CAAC,MAAM,IAAIJ,qBAAqB,EAAE;IAChCI,MAAM,GAAG,yCAAyC;EACpD,CAAC,MAAM;IACLA,MAAM,GAAG,mBAAmB;EAC9B;EAEA,OAAO;IACLC,GAAG,EAAE,mBAAmB;IACxBC,IAAI,EAAE;MACJC,OAAO,EAAE,EAAE;MACXC,KAAK,EAAE,eAAe;MACtBJ,MAAM;MACNN,IAAI;MACJW,KAAK,EAAEV,mBAAmB;MAC1BC,qBAAqB;MACrBU,MAAM,EAAE;QACNC,YAAY,EAAE,CACZ,YAAY,EACZ,QAAQ,EACR,sBAAsB,EACtB,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,EACzB,2BAA2B,EAC3B,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EAClB,OAAO,EACP,cAAc,EACd,iBAAiB,EACjB,YAAY,CACb;QACDC,iBAAiB,EAAE,CAAC,UAAU,CAAC;QAC/BC,iBAAiB,EAAE,CAAC,UAAU,EAAE,mBAAmB,EAAE,MAAM;MAC7D,CAAC;MACDC,OAAO,EAAE,CAAC,QAAQ,EAAE,oBAAoB;IAC1C;EACF,CAAC;AACH,CAAC","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "4.4.1-qa-staging.
|
|
3
|
+
"version": "4.4.1-qa-staging.27",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@fortawesome/fontawesome-svg-core": "^7.2.0",
|
|
35
35
|
"@fortawesome/react-native-fontawesome": "^0.3.2",
|
|
36
|
-
"@planningcenter/emoji-keyboard": "4.4.1-qa-staging.
|
|
36
|
+
"@planningcenter/emoji-keyboard": "4.4.1-qa-staging.27",
|
|
37
37
|
"lodash-inflection": "^1.5.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"sf-symbols-typescript": "^2.2.0",
|
|
85
85
|
"typescript": "~6.0.3"
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "692d0f5368988b4d99e2e79c94417a33f8cf8f55"
|
|
88
88
|
}
|
|
@@ -31,14 +31,24 @@ export const Conversations = ({ ListHeaderComponent }: ConversationsProps) => {
|
|
|
31
31
|
isRefetching,
|
|
32
32
|
isFetched,
|
|
33
33
|
hasNextPage,
|
|
34
|
-
args: {
|
|
34
|
+
args: {
|
|
35
|
+
chat_group_graph_id,
|
|
36
|
+
group_source_app_name,
|
|
37
|
+
show_direct_messages,
|
|
38
|
+
show_archived,
|
|
39
|
+
show_unread,
|
|
40
|
+
},
|
|
35
41
|
} = useConversationsContext()
|
|
36
42
|
const navigation = useNavigation()
|
|
37
43
|
const canCreateConversations = useCanCreateConversations()
|
|
38
44
|
const clearFilters = useClearConversationFilters()
|
|
39
45
|
const filterDropdownEnabled = useFilterDropdownEnabled()
|
|
40
46
|
const isFilterApplied =
|
|
41
|
-
!!chat_group_graph_id ||
|
|
47
|
+
!!chat_group_graph_id ||
|
|
48
|
+
!!group_source_app_name ||
|
|
49
|
+
!!show_direct_messages ||
|
|
50
|
+
!!show_archived ||
|
|
51
|
+
!!show_unread
|
|
42
52
|
const showArchivedResultsFooter = !!show_archived && !isLoading && !hasNextPage
|
|
43
53
|
const showFilteredResultsFooter =
|
|
44
54
|
filterDropdownEnabled &&
|
|
@@ -36,7 +36,7 @@ const FakeMenuView = ({ actions, onPressAction, children }: MenuViewProps) => {
|
|
|
36
36
|
)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
const configureAdapters = (menu?: MenuAdapter) => {
|
|
40
40
|
ChatAdapters.configure({
|
|
41
41
|
clipboard: new ClipboardAdapter({
|
|
42
42
|
getStringAsync: async () => '',
|
|
@@ -48,8 +48,12 @@ beforeAll(() => {
|
|
|
48
48
|
openCameraAsync: async () => ({ canceled: true, assets: null }),
|
|
49
49
|
openImageLibraryAsync: async () => ({ canceled: true, assets: null }),
|
|
50
50
|
}),
|
|
51
|
-
menu
|
|
51
|
+
menu,
|
|
52
52
|
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
configureAdapters(new MenuAdapter({ View: FakeMenuView }))
|
|
53
57
|
})
|
|
54
58
|
|
|
55
59
|
const options = [
|
|
@@ -111,4 +115,16 @@ describe('FilterDropdown', () => {
|
|
|
111
115
|
expect(onMoreFilters).toHaveBeenCalledTimes(1)
|
|
112
116
|
expect(onSelect).not.toHaveBeenCalled()
|
|
113
117
|
})
|
|
118
|
+
|
|
119
|
+
it('opens the popover menu when the host configured no menu', () => {
|
|
120
|
+
configureAdapters()
|
|
121
|
+
const { onSelect } = renderFilterDropdown()
|
|
122
|
+
|
|
123
|
+
expect(screen.queryAllByRole('menuitem')).toHaveLength(0)
|
|
124
|
+
|
|
125
|
+
fireEvent.press(screen.getByRole('button', { name: 'Groups' }))
|
|
126
|
+
fireEvent.press(screen.getByRole('menuitem', { name: 'Teams' }))
|
|
127
|
+
|
|
128
|
+
expect(onSelect).toHaveBeenCalledWith('teams')
|
|
129
|
+
})
|
|
114
130
|
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { fireEvent, render, screen } from '@testing-library/react-native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Text } from 'react-native'
|
|
4
|
+
import { MenuAction } from '../../../utils/native_adapters'
|
|
5
|
+
import { PopoverMenuView } from '../popover_menu_view'
|
|
6
|
+
|
|
7
|
+
const actions: MenuAction[] = [
|
|
8
|
+
{ id: 'all', title: 'All' },
|
|
9
|
+
{ id: 'groups', title: 'Groups', state: 'on' },
|
|
10
|
+
{ id: 'secret', title: 'Secret', attributes: { hidden: true } },
|
|
11
|
+
{
|
|
12
|
+
id: 'more',
|
|
13
|
+
title: '',
|
|
14
|
+
displayInline: true,
|
|
15
|
+
subactions: [{ id: 'more_filters', title: 'More filters' }],
|
|
16
|
+
},
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
const renderMenu = () => {
|
|
20
|
+
const onPressAction = jest.fn()
|
|
21
|
+
|
|
22
|
+
render(
|
|
23
|
+
<PopoverMenuView actions={actions} onPressAction={onPressAction}>
|
|
24
|
+
<Text>Trigger</Text>
|
|
25
|
+
</PopoverMenuView>
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
fireEvent.press(screen.getByText('Trigger'))
|
|
29
|
+
|
|
30
|
+
return { onPressAction }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('PopoverMenuView', () => {
|
|
34
|
+
it('opens with a row per visible action, inline sections flattened, the on action checked', () => {
|
|
35
|
+
renderMenu()
|
|
36
|
+
|
|
37
|
+
expect(screen.getAllByRole('menuitem').map(item => item.props.accessibilityState)).toEqual([
|
|
38
|
+
{ selected: false, disabled: false },
|
|
39
|
+
{ selected: true, disabled: false },
|
|
40
|
+
{ selected: false, disabled: false },
|
|
41
|
+
])
|
|
42
|
+
expect(screen.getByRole('menuitem', { name: 'More filters' })).toBeTruthy()
|
|
43
|
+
expect(screen.queryByRole('menuitem', { name: 'Secret' })).toBeNull()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('reports the pressed action by id and closes', () => {
|
|
47
|
+
const { onPressAction } = renderMenu()
|
|
48
|
+
|
|
49
|
+
fireEvent.press(screen.getByRole('menuitem', { name: 'More filters' }))
|
|
50
|
+
|
|
51
|
+
expect(onPressAction).toHaveBeenCalledWith({ nativeEvent: { event: 'more_filters' } })
|
|
52
|
+
expect(screen.queryAllByRole('menuitem')).toHaveLength(0)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('closes without an action when the scrim is pressed', () => {
|
|
56
|
+
const { onPressAction } = renderMenu()
|
|
57
|
+
|
|
58
|
+
fireEvent.press(screen.getByLabelText('Close menu'))
|
|
59
|
+
|
|
60
|
+
expect(onPressAction).not.toHaveBeenCalled()
|
|
61
|
+
expect(screen.queryAllByRole('menuitem')).toHaveLength(0)
|
|
62
|
+
})
|
|
63
|
+
})
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from '../../utils'
|
|
11
11
|
import { tokens } from '../../vendor/tapestry/tokens'
|
|
12
12
|
import { Icon } from './icon'
|
|
13
|
+
import { PopoverMenuView } from './popover_menu_view'
|
|
13
14
|
import { Text } from './text'
|
|
14
15
|
|
|
15
16
|
// =================================
|
|
@@ -35,6 +36,11 @@ export interface FilterDropdownProps {
|
|
|
35
36
|
onMoreFilters: () => void
|
|
36
37
|
triggerLabel: string
|
|
37
38
|
showMoreFilters?: boolean
|
|
39
|
+
/**
|
|
40
|
+
* Widest the trigger may render, in points. Hosts that measure the trigger at its intrinsic
|
|
41
|
+
* width need this for the label to truncate.
|
|
42
|
+
*/
|
|
43
|
+
maxWidth?: number
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
export function FilterDropdown({
|
|
@@ -44,8 +50,10 @@ export function FilterDropdown({
|
|
|
44
50
|
onMoreFilters,
|
|
45
51
|
triggerLabel,
|
|
46
52
|
showMoreFilters = true,
|
|
53
|
+
maxWidth,
|
|
47
54
|
}: FilterDropdownProps) {
|
|
48
55
|
const styles = useStyles()
|
|
56
|
+
const MenuView = Menu.View ?? PopoverMenuView
|
|
49
57
|
|
|
50
58
|
const optionActions: MenuAction[] = options.map(option => ({
|
|
51
59
|
id: option.id,
|
|
@@ -69,9 +77,9 @@ export function FilterDropdown({
|
|
|
69
77
|
}
|
|
70
78
|
|
|
71
79
|
return (
|
|
72
|
-
<
|
|
80
|
+
<MenuView actions={actions} onPressAction={handlePressAction} style={styles.container}>
|
|
73
81
|
<View
|
|
74
|
-
style={styles.trigger}
|
|
82
|
+
style={[styles.trigger, maxWidth !== undefined && { maxWidth }]}
|
|
75
83
|
accessible
|
|
76
84
|
accessibilityRole="button"
|
|
77
85
|
accessibilityHint="Opens filter options"
|
|
@@ -90,7 +98,7 @@ export function FilterDropdown({
|
|
|
90
98
|
accessibilityElementsHidden
|
|
91
99
|
/>
|
|
92
100
|
</View>
|
|
93
|
-
</
|
|
101
|
+
</MenuView>
|
|
94
102
|
)
|
|
95
103
|
}
|
|
96
104
|
|
|
@@ -25,6 +25,7 @@ export * from './text_inline_button'
|
|
|
25
25
|
export * from './text'
|
|
26
26
|
export * from './toggle_button'
|
|
27
27
|
export * from './filter_dropdown'
|
|
28
|
+
export * from './popover_menu_view'
|
|
28
29
|
export * from './keyboard_scroll_view'
|
|
29
30
|
export * from './keyboard_view'
|
|
30
31
|
export * from './platform_modal_header_buttons'
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { clamp } from 'lodash'
|
|
2
|
+
import React, { useRef, useState } from 'react'
|
|
3
|
+
import { Modal, Pressable, ScrollView, StyleSheet, useWindowDimensions, View } from 'react-native'
|
|
4
|
+
import { useChatContext } from '../../contexts/chat_context'
|
|
5
|
+
import { useCreateAndroidRippleColor, useFontScale, useTheme } from '../../hooks'
|
|
6
|
+
import { MenuAction, MenuViewProps, platformPressedOpacityStyle } from '../../utils'
|
|
7
|
+
import { tokens } from '../../vendor/tapestry/tokens'
|
|
8
|
+
import { Icon } from './icon'
|
|
9
|
+
import { Text } from './text'
|
|
10
|
+
|
|
11
|
+
// =================================
|
|
12
|
+
// ====== Constants ================
|
|
13
|
+
// =================================
|
|
14
|
+
|
|
15
|
+
const MENU_WIDTH = 240
|
|
16
|
+
const MENU_OFFSET = 4
|
|
17
|
+
const SCREEN_MARGIN = 16
|
|
18
|
+
|
|
19
|
+
const CLOSED_ANCHOR = { x: 0, y: 0, width: 0, height: 0 }
|
|
20
|
+
|
|
21
|
+
// =================================
|
|
22
|
+
// ====== Rows =====================
|
|
23
|
+
// =================================
|
|
24
|
+
|
|
25
|
+
type Row = { kind: 'action'; action: MenuAction } | { kind: 'separator' }
|
|
26
|
+
|
|
27
|
+
const actionId = (action: MenuAction) => action.id ?? action.title
|
|
28
|
+
|
|
29
|
+
const visibleActions = (actions: MenuAction[]) =>
|
|
30
|
+
actions.filter(action => !action.attributes?.hidden)
|
|
31
|
+
|
|
32
|
+
// Lays the actions out the way the native menus draw them: an inline section's
|
|
33
|
+
// subactions sit at the top level, divided from neighboring rows by a separator.
|
|
34
|
+
const buildRows = (actions: MenuAction[]): Row[] => {
|
|
35
|
+
const rows: Row[] = []
|
|
36
|
+
const pushSeparator = () => {
|
|
37
|
+
if (rows.length > 0 && rows[rows.length - 1].kind !== 'separator') {
|
|
38
|
+
rows.push({ kind: 'separator' })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
visibleActions(actions).forEach((action, index, visible) => {
|
|
43
|
+
if (action.displayInline && action.subactions) {
|
|
44
|
+
pushSeparator()
|
|
45
|
+
visibleActions(action.subactions).forEach(subaction =>
|
|
46
|
+
rows.push({ kind: 'action', action: subaction })
|
|
47
|
+
)
|
|
48
|
+
if (index < visible.length - 1) pushSeparator()
|
|
49
|
+
} else {
|
|
50
|
+
rows.push({ kind: 'action', action })
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
return rows
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// =================================
|
|
58
|
+
// ====== Component ================
|
|
59
|
+
// =================================
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A JS-only `MenuView` for hosts that cannot supply a native menu. Wraps the
|
|
63
|
+
* trigger in a pressable and opens a popover of the actions under it, or above
|
|
64
|
+
* it when the trigger sits in the lower half of the window.
|
|
65
|
+
*/
|
|
66
|
+
export function PopoverMenuView({
|
|
67
|
+
actions,
|
|
68
|
+
onPressAction,
|
|
69
|
+
onOpenMenu,
|
|
70
|
+
onCloseMenu,
|
|
71
|
+
style,
|
|
72
|
+
testID,
|
|
73
|
+
children,
|
|
74
|
+
}: MenuViewProps) {
|
|
75
|
+
const triggerRef = useRef<View>(null)
|
|
76
|
+
const [expanded, setExpanded] = useState(false)
|
|
77
|
+
const [anchor, setAnchor] = useState(CLOSED_ANCHOR)
|
|
78
|
+
const { edgeToEdge = true } = useChatContext()
|
|
79
|
+
const { width: windowWidth, height: windowHeight } = useWindowDimensions()
|
|
80
|
+
const fontScale = useFontScale()
|
|
81
|
+
const styles = useStyles()
|
|
82
|
+
|
|
83
|
+
const open = () => {
|
|
84
|
+
triggerRef.current?.measureInWindow((x, y, width, height) => {
|
|
85
|
+
setAnchor({ x, y, width, height })
|
|
86
|
+
})
|
|
87
|
+
setExpanded(true)
|
|
88
|
+
onOpenMenu?.()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const close = () => {
|
|
92
|
+
setExpanded(false)
|
|
93
|
+
onCloseMenu?.()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const handlePress = (action: MenuAction) => {
|
|
97
|
+
onPressAction?.({ nativeEvent: { event: actionId(action) } })
|
|
98
|
+
close()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const menuWidth = clamp(MENU_WIDTH * fontScale, MENU_WIDTH, windowWidth - SCREEN_MARGIN * 2)
|
|
102
|
+
const anchorBottom = anchor.y + anchor.height
|
|
103
|
+
const opensUpward = anchor.y + anchor.height / 2 > windowHeight / 2
|
|
104
|
+
const menuPosition = {
|
|
105
|
+
width: menuWidth,
|
|
106
|
+
left: clamp(
|
|
107
|
+
anchor.x,
|
|
108
|
+
SCREEN_MARGIN,
|
|
109
|
+
Math.max(SCREEN_MARGIN, windowWidth - menuWidth - SCREEN_MARGIN)
|
|
110
|
+
),
|
|
111
|
+
...(opensUpward
|
|
112
|
+
? {
|
|
113
|
+
bottom: windowHeight - anchor.y + MENU_OFFSET,
|
|
114
|
+
maxHeight: anchor.y - MENU_OFFSET - SCREEN_MARGIN,
|
|
115
|
+
}
|
|
116
|
+
: {
|
|
117
|
+
top: anchorBottom + MENU_OFFSET,
|
|
118
|
+
maxHeight: windowHeight - anchorBottom - MENU_OFFSET - SCREEN_MARGIN,
|
|
119
|
+
}),
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<>
|
|
124
|
+
<Pressable ref={triggerRef} style={style} testID={testID} onPress={open} accessible={false}>
|
|
125
|
+
{children}
|
|
126
|
+
</Pressable>
|
|
127
|
+
<Modal
|
|
128
|
+
visible={expanded}
|
|
129
|
+
transparent
|
|
130
|
+
animationType="fade"
|
|
131
|
+
statusBarTranslucent={edgeToEdge}
|
|
132
|
+
navigationBarTranslucent={edgeToEdge}
|
|
133
|
+
onRequestClose={close}
|
|
134
|
+
>
|
|
135
|
+
<Pressable
|
|
136
|
+
style={styles.scrim}
|
|
137
|
+
onPress={close}
|
|
138
|
+
accessibilityRole="button"
|
|
139
|
+
accessibilityLabel="Close menu"
|
|
140
|
+
/>
|
|
141
|
+
<View style={[styles.menu, menuPosition]} accessibilityRole="menu">
|
|
142
|
+
<ScrollView bounces={false}>
|
|
143
|
+
{buildRows(actions).map((row, index) =>
|
|
144
|
+
row.kind === 'separator' ? (
|
|
145
|
+
<View key={index} style={styles.separator} />
|
|
146
|
+
) : (
|
|
147
|
+
<PopoverMenuItem
|
|
148
|
+
key={index}
|
|
149
|
+
action={row.action}
|
|
150
|
+
onPress={() => handlePress(row.action)}
|
|
151
|
+
/>
|
|
152
|
+
)
|
|
153
|
+
)}
|
|
154
|
+
</ScrollView>
|
|
155
|
+
</View>
|
|
156
|
+
</Modal>
|
|
157
|
+
</>
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
interface PopoverMenuItemProps {
|
|
162
|
+
action: MenuAction
|
|
163
|
+
onPress: () => void
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function PopoverMenuItem({ action, onPress }: PopoverMenuItemProps) {
|
|
167
|
+
const styles = useStyles()
|
|
168
|
+
const { colors } = useTheme()
|
|
169
|
+
const androidRippleColor = useCreateAndroidRippleColor({ color: colors.fillColorNeutral050Base })
|
|
170
|
+
const selected = action.state === 'on'
|
|
171
|
+
const disabled = action.attributes?.disabled === true
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<Pressable
|
|
175
|
+
style={({ pressed }) => [
|
|
176
|
+
styles.item,
|
|
177
|
+
pressed && platformPressedOpacityStyle,
|
|
178
|
+
disabled && styles.itemDisabled,
|
|
179
|
+
]}
|
|
180
|
+
onPress={onPress}
|
|
181
|
+
disabled={disabled}
|
|
182
|
+
accessibilityRole="menuitem"
|
|
183
|
+
accessibilityState={{ selected, disabled }}
|
|
184
|
+
android_ripple={{ color: androidRippleColor, borderless: false, foreground: true }}
|
|
185
|
+
>
|
|
186
|
+
<Text style={styles.itemLabel}>{action.title}</Text>
|
|
187
|
+
{selected && (
|
|
188
|
+
<Icon name="general.check" style={styles.itemCheck} accessibilityElementsHidden />
|
|
189
|
+
)}
|
|
190
|
+
</Pressable>
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// =================================
|
|
195
|
+
// ====== Styles ===================
|
|
196
|
+
// =================================
|
|
197
|
+
|
|
198
|
+
const useStyles = () => {
|
|
199
|
+
const { colors } = useTheme()
|
|
200
|
+
|
|
201
|
+
return StyleSheet.create({
|
|
202
|
+
scrim: {
|
|
203
|
+
...StyleSheet.absoluteFill,
|
|
204
|
+
},
|
|
205
|
+
menu: {
|
|
206
|
+
position: 'absolute',
|
|
207
|
+
paddingVertical: 4,
|
|
208
|
+
borderRadius: 8,
|
|
209
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
210
|
+
borderColor: colors.fillColorNeutral050Base,
|
|
211
|
+
backgroundColor: colors.fillColorNeutral100Inverted,
|
|
212
|
+
boxShadow: '0px 4px 12px rgba(0, 0, 0, 0.15)',
|
|
213
|
+
elevation: 4,
|
|
214
|
+
overflow: 'hidden',
|
|
215
|
+
},
|
|
216
|
+
item: {
|
|
217
|
+
flexDirection: 'row',
|
|
218
|
+
alignItems: 'center',
|
|
219
|
+
gap: 12,
|
|
220
|
+
paddingHorizontal: 16,
|
|
221
|
+
paddingVertical: 12,
|
|
222
|
+
},
|
|
223
|
+
itemDisabled: {
|
|
224
|
+
opacity: 0.4,
|
|
225
|
+
},
|
|
226
|
+
itemLabel: {
|
|
227
|
+
flex: 1,
|
|
228
|
+
},
|
|
229
|
+
itemCheck: {
|
|
230
|
+
fontSize: tokens.fontSizeSm,
|
|
231
|
+
color: colors.interaction,
|
|
232
|
+
},
|
|
233
|
+
separator: {
|
|
234
|
+
height: StyleSheet.hairlineWidth,
|
|
235
|
+
marginVertical: 4,
|
|
236
|
+
backgroundColor: colors.fillColorNeutral050Base,
|
|
237
|
+
},
|
|
238
|
+
})
|
|
239
|
+
}
|
|
@@ -45,7 +45,13 @@ export const ConversationsContextProvider = ({
|
|
|
45
45
|
opts?: ApiGetQueryOptions
|
|
46
46
|
}>) => {
|
|
47
47
|
const [activeConversationId, setActiveConversationId] = useState<number | undefined>()
|
|
48
|
-
const {
|
|
48
|
+
const {
|
|
49
|
+
chat_group_graph_id,
|
|
50
|
+
group_source_app_name,
|
|
51
|
+
show_direct_messages,
|
|
52
|
+
show_archived,
|
|
53
|
+
show_unread,
|
|
54
|
+
} = args
|
|
49
55
|
|
|
50
56
|
const query = useConversations(
|
|
51
57
|
{
|
|
@@ -53,6 +59,7 @@ export const ConversationsContextProvider = ({
|
|
|
53
59
|
group_source_app_name,
|
|
54
60
|
show_direct_messages,
|
|
55
61
|
show_archived,
|
|
62
|
+
show_unread,
|
|
56
63
|
},
|
|
57
64
|
paginatorOptions
|
|
58
65
|
)
|