@planningcenter/chat-react-native 4.0.1-qa-staging.1 → 4.0.1-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/build/components/conversation/message.d.ts +2 -3
  2. package/build/components/conversation/message.d.ts.map +1 -1
  3. package/build/components/conversation/message.js +22 -23
  4. package/build/components/conversation/message.js.map +1 -1
  5. package/build/components/conversation/message_read_receipts.d.ts +4 -2
  6. package/build/components/conversation/message_read_receipts.d.ts.map +1 -1
  7. package/build/components/conversation/message_read_receipts.js +3 -2
  8. package/build/components/conversation/message_read_receipts.js.map +1 -1
  9. package/build/components/conversation/reply_shadow_message.d.ts +1 -2
  10. package/build/components/conversation/reply_shadow_message.d.ts.map +1 -1
  11. package/build/components/conversation/reply_shadow_message.js +46 -47
  12. package/build/components/conversation/reply_shadow_message.js.map +1 -1
  13. package/build/components/primitive/form_sheet.d.ts +1 -2
  14. package/build/components/primitive/form_sheet.d.ts.map +1 -1
  15. package/build/components/primitive/form_sheet.js +53 -68
  16. package/build/components/primitive/form_sheet.js.map +1 -1
  17. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  18. package/build/hooks/use_conversation_messages.js +28 -40
  19. package/build/hooks/use_conversation_messages.js.map +1 -1
  20. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
  21. package/build/hooks/use_conversation_messages_jolt_events.js +1 -6
  22. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
  23. package/build/hooks/use_message_create_or_update.d.ts +4 -99
  24. package/build/hooks/use_message_create_or_update.d.ts.map +1 -1
  25. package/build/hooks/use_message_create_or_update.js +6 -47
  26. package/build/hooks/use_message_create_or_update.js.map +1 -1
  27. package/build/screens/conversation_new/components/groups_form.js +80 -71
  28. package/build/screens/conversation_new/components/groups_form.js.map +1 -1
  29. package/build/screens/conversation_screen.d.ts.map +1 -1
  30. package/build/screens/conversation_screen.js +365 -184
  31. package/build/screens/conversation_screen.js.map +1 -1
  32. package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
  33. package/build/screens/conversation_select_type_screen.js +98 -82
  34. package/build/screens/conversation_select_type_screen.js.map +1 -1
  35. package/build/types/resources/message.d.ts +0 -2
  36. package/build/types/resources/message.d.ts.map +1 -1
  37. package/build/types/resources/message.js.map +1 -1
  38. package/build/utils/cache/messages_cache.d.ts +0 -1
  39. package/build/utils/cache/messages_cache.d.ts.map +1 -1
  40. package/build/utils/cache/messages_cache.js +7 -14
  41. package/build/utils/cache/messages_cache.js.map +1 -1
  42. package/build/utils/cache/optimistically_create_message.d.ts +1 -2
  43. package/build/utils/cache/optimistically_create_message.d.ts.map +1 -1
  44. package/build/utils/cache/optimistically_create_message.js +2 -4
  45. package/build/utils/cache/optimistically_create_message.js.map +1 -1
  46. package/build/utils/client/transform_response.d.ts.map +1 -1
  47. package/build/utils/client/transform_response.js +5 -9
  48. package/build/utils/client/transform_response.js.map +1 -1
  49. package/build/utils/group_messages.d.ts +0 -1
  50. package/build/utils/group_messages.d.ts.map +1 -1
  51. package/build/utils/group_messages.js +1 -10
  52. package/build/utils/group_messages.js.map +1 -1
  53. package/build/utils/jolt/transform_message_event_data_to_message_resource.d.ts.map +1 -1
  54. package/build/utils/jolt/transform_message_event_data_to_message_resource.js +0 -1
  55. package/build/utils/jolt/transform_message_event_data_to_message_resource.js.map +1 -1
  56. package/build/utils/request/messages_data_options.d.ts.map +1 -1
  57. package/build/utils/request/messages_data_options.js +2 -2
  58. package/build/utils/request/messages_data_options.js.map +1 -1
  59. package/package.json +3 -3
  60. package/src/components/conversation/message.tsx +18 -15
  61. package/src/components/conversation/message_read_receipts.tsx +5 -3
  62. package/src/components/conversation/reply_shadow_message.tsx +7 -9
  63. package/src/components/primitive/form_sheet.tsx +3 -10
  64. package/src/hooks/use_conversation_messages.ts +1 -5
  65. package/src/hooks/use_conversation_messages_jolt_events.ts +0 -7
  66. package/src/hooks/use_message_create_or_update.ts +16 -29
  67. package/src/screens/conversation_new/components/groups_form.tsx +7 -2
  68. package/src/screens/conversation_screen.tsx +104 -11
  69. package/src/screens/conversation_select_type_screen.tsx +9 -3
  70. package/src/types/resources/message.ts +0 -2
  71. package/src/utils/__tests__/group_messages.test.ts +0 -48
  72. package/src/utils/cache/messages_cache.ts +11 -27
  73. package/src/utils/cache/optimistically_create_message.ts +0 -3
  74. package/src/utils/client/transform_response.ts +5 -7
  75. package/src/utils/group_messages.ts +1 -18
  76. package/src/utils/jolt/transform_message_event_data_to_message_resource.ts +0 -1
  77. package/src/utils/request/messages_data_options.ts +1 -2
  78. package/build/components/conversation/message_list.d.ts +0 -21
  79. package/build/components/conversation/message_list.d.ts.map +0 -1
  80. package/build/components/conversation/message_list.js +0 -273
  81. package/build/components/conversation/message_list.js.map +0 -1
  82. package/build/utils/replace_equal_by_id.d.ts +0 -6
  83. package/build/utils/replace_equal_by_id.d.ts.map +0 -1
  84. package/build/utils/replace_equal_by_id.js +0 -41
  85. package/build/utils/replace_equal_by_id.js.map +0 -1
  86. package/src/components/conversation/__tests__/message_list.test.tsx +0 -271
  87. package/src/components/conversation/__tests__/reply_shadow_message.test.tsx +0 -119
  88. package/src/components/conversation/message_list.tsx +0 -157
  89. package/src/hooks/__tests__/use_message_create_or_update.test.tsx +0 -110
  90. package/src/utils/__tests__/replace_equal_by_id.test.ts +0 -73
  91. package/src/utils/cache/__tests__/messages_cache.test.ts +0 -89
  92. package/src/utils/cache/__tests__/messages_cache_reply_roots.test.ts +0 -70
  93. package/src/utils/client/__tests__/transform_response.test.ts +0 -62
  94. package/src/utils/replace_equal_by_id.ts +0 -42
@@ -1,19 +1,21 @@
1
1
  import { getRequestQueryKey } from '../../hooks/use_suspense_api';
2
2
  import { transformReactionEventDataToReactionCountResource } from '../jolt/transform_reaction_event_data_to_reaction_count_resource';
3
3
  import { getMessagesRequestArgs } from '../request/get_messages';
4
- import { updateAllRecordsInPagesData, updateOrCreateRecordInPagesData, updateRecordInPagesData } from './page_mutations';
4
+ import { updateOrCreateRecordInPagesData, updateRecordInPagesData } from './page_mutations';
5
5
  import { deleteRecordInPagesData } from './page_mutations';
6
6
  export function updateCacheWithMessage(queryClient, queryKey, message, event) {
7
7
  queryClient.setQueryData(queryKey, prev => {
8
8
  if (event === 'message.created') {
9
- // Before adding the new message, remove its pending temporary counterpart.
10
- // The Jolt echo can arrive before the HTTP response has swapped it out.
9
+ // Before adding the new message, remove any pending temporary messages
10
+ // with matching text to prevent duplicates from race conditions
11
11
  let dataAfterTempRemoval = prev;
12
- if (prev && message.mine && message.idempotentKey) {
12
+ if (prev && message.text && message.mine) {
13
13
  dataAfterTempRemoval = deleteRecordInPagesData({
14
14
  data: prev,
15
15
  record: message,
16
- matchFn: existingMessage => isTemporaryMessageId(existingMessage.id) && existingMessage.idempotentKey === message.idempotentKey
16
+ matchFn: (existingMessage, _record) => {
17
+ return isTemporaryMessageId(existingMessage.id) && existingMessage.text === message.text && existingMessage.mine;
18
+ }
17
19
  });
18
20
  }
19
21
  return updateOrCreateRecordInPagesData({
@@ -45,15 +47,6 @@ export function updateCacheWithIndividualMessage(queryClient, queryKey, message)
45
47
  };
46
48
  });
47
49
  }
48
- export function updateCacheReplyRoots(queryClient, queryKey, root) {
49
- queryClient.setQueryData(queryKey, prev => updateAllRecordsInPagesData({
50
- data: prev,
51
- processRecord: message => message.replyRoot?.id === root.id ? {
52
- ...message,
53
- replyRoot: mergeMessageUpdate(root, message.replyRoot)
54
- } : message
55
- }));
56
- }
57
50
  export function updateCacheWithReaction(queryClient, queryKey, event, currentPersonId) {
58
51
  const message = {
59
52
  id: event.data.data.message_sort_key
@@ -1 +1 @@
1
- {"version":3,"file":"messages_cache.js","names":["getRequestQueryKey","transformReactionEventDataToReactionCountResource","getMessagesRequestArgs","updateAllRecordsInPagesData","updateOrCreateRecordInPagesData","updateRecordInPagesData","deleteRecordInPagesData","updateCacheWithMessage","queryClient","queryKey","message","event","setQueryData","prev","dataAfterTempRemoval","mine","idempotentKey","data","record","matchFn","existingMessage","isTemporaryMessageId","id","processRecord","current","mergeMessageUpdate","updateCacheWithIndividualMessage","links","meta","updateCacheReplyRoots","root","replyRoot","updateCacheWithReaction","currentPersonId","message_sort_key","oldMessage","reactionCounts","foundMatch","newReactionCounts","map","reactionCount","value","oldData","newReactionCount","count","messageId","endsWith","isNewMessage","getThreadedMessagesQueryKey","conversationId","replyRootId","requestArgs","conversation_id","reply_root_id"],"sources":["../../../src/utils/cache/messages_cache.ts"],"sourcesContent":["import { InfiniteData, QueryClient } from '@tanstack/react-query'\nimport { getRequestQueryKey } from '../../hooks/use_suspense_api'\nimport { ApiCollection, ApiResource, MessageResource } from '../../types'\nimport { JoltReactionEvent } from '../../types/jolt_events'\nimport { transformReactionEventDataToReactionCountResource } from '../jolt/transform_reaction_event_data_to_reaction_count_resource'\nimport { getMessagesRequestArgs } from '../request/get_messages'\nimport {\n updateAllRecordsInPagesData,\n updateOrCreateRecordInPagesData,\n updateRecordInPagesData,\n} from './page_mutations'\nimport { deleteRecordInPagesData } from './page_mutations'\n\nexport function updateCacheWithMessage(\n queryClient: QueryClient,\n queryKey: unknown[],\n message: MessageResource,\n event: 'message.created' | 'message.updated'\n) {\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev => {\n if (event === 'message.created') {\n // Before adding the new message, remove its pending temporary counterpart.\n // The Jolt echo can arrive before the HTTP response has swapped it out.\n let dataAfterTempRemoval = prev\n if (prev && message.mine && message.idempotentKey) {\n dataAfterTempRemoval = deleteRecordInPagesData({\n data: prev,\n record: message,\n matchFn: existingMessage =>\n isTemporaryMessageId(existingMessage.id) &&\n existingMessage.idempotentKey === message.idempotentKey,\n })\n }\n\n return updateOrCreateRecordInPagesData({\n data: dataAfterTempRemoval,\n record: message,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n } else {\n return updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n }\n })\n}\n\ntype IndividualMessageQueryData = ApiResource<MessageResource>\n\nexport function updateCacheWithIndividualMessage(\n queryClient: QueryClient,\n queryKey: unknown[],\n message: MessageResource\n) {\n queryClient.setQueryData<IndividualMessageQueryData>(queryKey, prev => {\n if (!prev) {\n return {\n data: message,\n links: {},\n meta: {},\n }\n }\n\n return {\n ...prev,\n data: mergeMessageUpdate(message, prev.data),\n }\n })\n}\n\nexport function updateCacheReplyRoots(\n queryClient: QueryClient,\n queryKey: unknown[],\n root: MessageResource\n) {\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev =>\n updateAllRecordsInPagesData({\n data: prev,\n processRecord: message =>\n message.replyRoot?.id === root.id\n ? { ...message, replyRoot: mergeMessageUpdate(root, message.replyRoot) }\n : message,\n })\n )\n}\n\nexport function updateCacheWithReaction(\n queryClient: QueryClient,\n queryKey: unknown[],\n event: JoltReactionEvent,\n currentPersonId: number\n) {\n const message = { id: event.data.data.message_sort_key } as MessageResource\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev =>\n updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, oldMessage) => {\n const reactionCounts = oldMessage.reactionCounts || []\n let foundMatch = false\n let newReactionCounts = reactionCounts.map(reactionCount => {\n if (reactionCount.value === event.data.data.value) {\n foundMatch = true\n return transformReactionEventDataToReactionCountResource({\n data: event.data.data,\n oldData: reactionCount,\n event: event.event,\n currentPersonId,\n })\n }\n return reactionCount\n })\n\n if (!foundMatch) {\n const newReactionCount = transformReactionEventDataToReactionCountResource({\n data: event.data.data,\n event: event.event,\n currentPersonId,\n })\n\n if (newReactionCount?.count) {\n newReactionCounts = [...newReactionCounts, newReactionCount]\n }\n }\n\n return { ...oldMessage, reactionCounts: newReactionCounts }\n },\n })\n )\n}\n\ntype MessagesQueryData = InfiniteData<ApiCollection<MessageResource>>\nexport function isTemporaryMessageId(messageId?: string | null): boolean {\n return !!messageId && messageId.endsWith('-temp')\n}\nexport function isNewMessage(message?: MessageResource): boolean {\n return !message?.id || isTemporaryMessageId(message.id)\n}\n\nexport function getThreadedMessagesQueryKey(conversationId: number, replyRootId: string) {\n const requestArgs = getMessagesRequestArgs({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n return getRequestQueryKey(requestArgs)\n}\n\nexport function mergeMessageUpdate(\n record: MessageResource,\n current?: MessageResource\n): MessageResource {\n if (!current) {\n return record\n }\n\n return {\n ...current,\n ...record,\n // Preserve reactions from cache - they're managed via separate reaction events\n reactionCounts: current.reactionCounts || [],\n }\n}\n"],"mappings":"AACA,SAASA,kBAAkB,QAAQ,8BAA8B;AAGjE,SAASC,iDAAiD,QAAQ,kEAAkE;AACpI,SAASC,sBAAsB,QAAQ,yBAAyB;AAChE,SACEC,2BAA2B,EAC3BC,+BAA+B,EAC/BC,uBAAuB,QAClB,kBAAkB;AACzB,SAASC,uBAAuB,QAAQ,kBAAkB;AAE1D,OAAO,SAASC,sBAAsBA,CACpCC,WAAwB,EACxBC,QAAmB,EACnBC,OAAwB,EACxBC,KAA4C,EAC5C;EACAH,WAAW,CAACI,YAAY,CAAoBH,QAAQ,EAAEI,IAAI,IAAI;IAC5D,IAAIF,KAAK,KAAK,iBAAiB,EAAE;MAC/B;MACA;MACA,IAAIG,oBAAoB,GAAGD,IAAI;MAC/B,IAAIA,IAAI,IAAIH,OAAO,CAACK,IAAI,IAAIL,OAAO,CAACM,aAAa,EAAE;QACjDF,oBAAoB,GAAGR,uBAAuB,CAAC;UAC7CW,IAAI,EAAEJ,IAAI;UACVK,MAAM,EAAER,OAAO;UACfS,OAAO,EAAEC,eAAe,IACtBC,oBAAoB,CAACD,eAAe,CAACE,EAAE,CAAC,IACxCF,eAAe,CAACJ,aAAa,KAAKN,OAAO,CAACM;QAC9C,CAAC,CAAC;MACJ;MAEA,OAAOZ,+BAA+B,CAAC;QACrCa,IAAI,EAAEH,oBAAoB;QAC1BI,MAAM,EAAER,OAAO;QACfa,aAAa,EAAEA,CAACL,MAAM,EAAEM,OAAO,KAAKC,kBAAkB,CAACP,MAAM,EAAEM,OAAO;MACxE,CAAC,CAAC;IACJ,CAAC,MAAM;MACL,OAAOnB,uBAAuB,CAAC;QAC7BY,IAAI,EAAEJ,IAAI;QACVK,MAAM,EAAER,OAAO;QACfa,aAAa,EAAEA,CAACL,MAAM,EAAEM,OAAO,KAAKC,kBAAkB,CAACP,MAAM,EAAEM,OAAO;MACxE,CAAC,CAAC;IACJ;EACF,CAAC,CAAC;AACJ;AAIA,OAAO,SAASE,gCAAgCA,CAC9ClB,WAAwB,EACxBC,QAAmB,EACnBC,OAAwB,EACxB;EACAF,WAAW,CAACI,YAAY,CAA6BH,QAAQ,EAAEI,IAAI,IAAI;IACrE,IAAI,CAACA,IAAI,EAAE;MACT,OAAO;QACLI,IAAI,EAAEP,OAAO;QACbiB,KAAK,EAAE,CAAC,CAAC;QACTC,IAAI,EAAE,CAAC;MACT,CAAC;IACH;IAEA,OAAO;MACL,GAAGf,IAAI;MACPI,IAAI,EAAEQ,kBAAkB,CAACf,OAAO,EAAEG,IAAI,CAACI,IAAI;IAC7C,CAAC;EACH,CAAC,CAAC;AACJ;AAEA,OAAO,SAASY,qBAAqBA,CACnCrB,WAAwB,EACxBC,QAAmB,EACnBqB,IAAqB,EACrB;EACAtB,WAAW,CAACI,YAAY,CAAoBH,QAAQ,EAAEI,IAAI,IACxDV,2BAA2B,CAAC;IAC1Bc,IAAI,EAAEJ,IAAI;IACVU,aAAa,EAAEb,OAAO,IACpBA,OAAO,CAACqB,SAAS,EAAET,EAAE,KAAKQ,IAAI,CAACR,EAAE,GAC7B;MAAE,GAAGZ,OAAO;MAAEqB,SAAS,EAAEN,kBAAkB,CAACK,IAAI,EAAEpB,OAAO,CAACqB,SAAS;IAAE,CAAC,GACtErB;EACR,CAAC,CACH,CAAC;AACH;AAEA,OAAO,SAASsB,uBAAuBA,CACrCxB,WAAwB,EACxBC,QAAmB,EACnBE,KAAwB,EACxBsB,eAAuB,EACvB;EACA,MAAMvB,OAAO,GAAG;IAAEY,EAAE,EAAEX,KAAK,CAACM,IAAI,CAACA,IAAI,CAACiB;EAAiB,CAAoB;EAC3E1B,WAAW,CAACI,YAAY,CAAoBH,QAAQ,EAAEI,IAAI,IACxDR,uBAAuB,CAAC;IACtBY,IAAI,EAAEJ,IAAI;IACVK,MAAM,EAAER,OAAO;IACfa,aAAa,EAAEA,CAACL,MAAM,EAAEiB,UAAU,KAAK;MACrC,MAAMC,cAAc,GAAGD,UAAU,CAACC,cAAc,IAAI,EAAE;MACtD,IAAIC,UAAU,GAAG,KAAK;MACtB,IAAIC,iBAAiB,GAAGF,cAAc,CAACG,GAAG,CAACC,aAAa,IAAI;QAC1D,IAAIA,aAAa,CAACC,KAAK,KAAK9B,KAAK,CAACM,IAAI,CAACA,IAAI,CAACwB,KAAK,EAAE;UACjDJ,UAAU,GAAG,IAAI;UACjB,OAAOpC,iDAAiD,CAAC;YACvDgB,IAAI,EAAEN,KAAK,CAACM,IAAI,CAACA,IAAI;YACrByB,OAAO,EAAEF,aAAa;YACtB7B,KAAK,EAAEA,KAAK,CAACA,KAAK;YAClBsB;UACF,CAAC,CAAC;QACJ;QACA,OAAOO,aAAa;MACtB,CAAC,CAAC;MAEF,IAAI,CAACH,UAAU,EAAE;QACf,MAAMM,gBAAgB,GAAG1C,iDAAiD,CAAC;UACzEgB,IAAI,EAAEN,KAAK,CAACM,IAAI,CAACA,IAAI;UACrBN,KAAK,EAAEA,KAAK,CAACA,KAAK;UAClBsB;QACF,CAAC,CAAC;QAEF,IAAIU,gBAAgB,EAAEC,KAAK,EAAE;UAC3BN,iBAAiB,GAAG,CAAC,GAAGA,iBAAiB,EAAEK,gBAAgB,CAAC;QAC9D;MACF;MAEA,OAAO;QAAE,GAAGR,UAAU;QAAEC,cAAc,EAAEE;MAAkB,CAAC;IAC7D;EACF,CAAC,CACH,CAAC;AACH;AAGA,OAAO,SAASjB,oBAAoBA,CAACwB,SAAyB,EAAW;EACvE,OAAO,CAAC,CAACA,SAAS,IAAIA,SAAS,CAACC,QAAQ,CAAC,OAAO,CAAC;AACnD;AACA,OAAO,SAASC,YAAYA,CAACrC,OAAyB,EAAW;EAC/D,OAAO,CAACA,OAAO,EAAEY,EAAE,IAAID,oBAAoB,CAACX,OAAO,CAACY,EAAE,CAAC;AACzD;AAEA,OAAO,SAAS0B,2BAA2BA,CAACC,cAAsB,EAAEC,WAAmB,EAAE;EACvF,MAAMC,WAAW,GAAGjD,sBAAsB,CAAC;IACzCkD,eAAe,EAAEH,cAAc;IAC/BI,aAAa,EAAEH;EACjB,CAAC,CAAC;EACF,OAAOlD,kBAAkB,CAACmD,WAAW,CAAC;AACxC;AAEA,OAAO,SAAS1B,kBAAkBA,CAChCP,MAAuB,EACvBM,OAAyB,EACR;EACjB,IAAI,CAACA,OAAO,EAAE;IACZ,OAAON,MAAM;EACf;EAEA,OAAO;IACL,GAAGM,OAAO;IACV,GAAGN,MAAM;IACT;IACAkB,cAAc,EAAEZ,OAAO,CAACY,cAAc,IAAI;EAC5C,CAAC;AACH","ignoreList":[]}
1
+ {"version":3,"file":"messages_cache.js","names":["getRequestQueryKey","transformReactionEventDataToReactionCountResource","getMessagesRequestArgs","updateOrCreateRecordInPagesData","updateRecordInPagesData","deleteRecordInPagesData","updateCacheWithMessage","queryClient","queryKey","message","event","setQueryData","prev","dataAfterTempRemoval","text","mine","data","record","matchFn","existingMessage","_record","isTemporaryMessageId","id","processRecord","current","mergeMessageUpdate","updateCacheWithIndividualMessage","links","meta","updateCacheWithReaction","currentPersonId","message_sort_key","oldMessage","reactionCounts","foundMatch","newReactionCounts","map","reactionCount","value","oldData","newReactionCount","count","messageId","endsWith","isNewMessage","getThreadedMessagesQueryKey","conversationId","replyRootId","requestArgs","conversation_id","reply_root_id"],"sources":["../../../src/utils/cache/messages_cache.ts"],"sourcesContent":["import { InfiniteData, QueryClient } from '@tanstack/react-query'\nimport { getRequestQueryKey } from '../../hooks/use_suspense_api'\nimport { ApiCollection, ApiResource, MessageResource } from '../../types'\nimport { JoltReactionEvent } from '../../types/jolt_events'\nimport { transformReactionEventDataToReactionCountResource } from '../jolt/transform_reaction_event_data_to_reaction_count_resource'\nimport { getMessagesRequestArgs } from '../request/get_messages'\nimport { updateOrCreateRecordInPagesData, updateRecordInPagesData } from './page_mutations'\nimport { deleteRecordInPagesData } from './page_mutations'\n\nexport function updateCacheWithMessage(\n queryClient: QueryClient,\n queryKey: unknown[],\n message: MessageResource,\n event: 'message.created' | 'message.updated'\n) {\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev => {\n if (event === 'message.created') {\n // Before adding the new message, remove any pending temporary messages\n // with matching text to prevent duplicates from race conditions\n let dataAfterTempRemoval = prev\n if (prev && message.text && message.mine) {\n dataAfterTempRemoval = deleteRecordInPagesData({\n data: prev,\n record: message,\n matchFn: (existingMessage, _record) => {\n return (\n isTemporaryMessageId(existingMessage.id) &&\n existingMessage.text === message.text &&\n existingMessage.mine\n )\n },\n })\n }\n\n return updateOrCreateRecordInPagesData({\n data: dataAfterTempRemoval,\n record: message,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n } else {\n return updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n }\n })\n}\n\ntype IndividualMessageQueryData = ApiResource<MessageResource>\n\nexport function updateCacheWithIndividualMessage(\n queryClient: QueryClient,\n queryKey: unknown[],\n message: MessageResource\n) {\n queryClient.setQueryData<IndividualMessageQueryData>(queryKey, prev => {\n if (!prev) {\n return {\n data: message,\n links: {},\n meta: {},\n }\n }\n\n return {\n ...prev,\n data: mergeMessageUpdate(message, prev.data),\n }\n })\n}\n\nexport function updateCacheWithReaction(\n queryClient: QueryClient,\n queryKey: unknown[],\n event: JoltReactionEvent,\n currentPersonId: number\n) {\n const message = { id: event.data.data.message_sort_key } as MessageResource\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev =>\n updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, oldMessage) => {\n const reactionCounts = oldMessage.reactionCounts || []\n let foundMatch = false\n let newReactionCounts = reactionCounts.map(reactionCount => {\n if (reactionCount.value === event.data.data.value) {\n foundMatch = true\n return transformReactionEventDataToReactionCountResource({\n data: event.data.data,\n oldData: reactionCount,\n event: event.event,\n currentPersonId,\n })\n }\n return reactionCount\n })\n\n if (!foundMatch) {\n const newReactionCount = transformReactionEventDataToReactionCountResource({\n data: event.data.data,\n event: event.event,\n currentPersonId,\n })\n\n if (newReactionCount?.count) {\n newReactionCounts = [...newReactionCounts, newReactionCount]\n }\n }\n\n return { ...oldMessage, reactionCounts: newReactionCounts }\n },\n })\n )\n}\n\ntype MessagesQueryData = InfiniteData<ApiCollection<MessageResource>>\nexport function isTemporaryMessageId(messageId?: string | null): boolean {\n return !!messageId && messageId.endsWith('-temp')\n}\nexport function isNewMessage(message?: MessageResource): boolean {\n return !message?.id || isTemporaryMessageId(message.id)\n}\n\nexport function getThreadedMessagesQueryKey(conversationId: number, replyRootId: string) {\n const requestArgs = getMessagesRequestArgs({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n return getRequestQueryKey(requestArgs)\n}\n\nexport function mergeMessageUpdate(\n record: MessageResource,\n current?: MessageResource\n): MessageResource {\n if (!current) {\n return record\n }\n\n return {\n ...current,\n ...record,\n // Preserve reactions from cache - they're managed via separate reaction events\n reactionCounts: current.reactionCounts || [],\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,12 +1,11 @@
1
1
  import { CurrentPersonResource, MessageResource } from '../../types';
2
2
  import { DenormalizedAttachmentResourceForCreate } from '../../types/resources/denormalized_attachment_resource_for_create';
3
- export declare function optimisticallyCreateMessage({ conversationId, text, attachments, currentPerson, message, replyRootId, idempotentKey, }: {
3
+ export declare function optimisticallyCreateMessage({ conversationId, text, attachments, currentPerson, message, replyRootId, }: {
4
4
  conversationId: number;
5
5
  text: string;
6
6
  attachments?: DenormalizedAttachmentResourceForCreate[];
7
7
  currentPerson: CurrentPersonResource;
8
8
  message?: MessageResource;
9
9
  replyRootId?: string | null;
10
- idempotentKey?: string;
11
10
  }): MessageResource;
12
11
  //# sourceMappingURL=optimistically_create_message.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"optimistically_create_message.d.ts","sourceRoot":"","sources":["../../../src/utils/cache/optimistically_create_message.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,qBAAqB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAEnF,OAAO,EAAE,uCAAuC,EAAE,MAAM,mEAAmE,CAAA;AAM3H,wBAAgB,2BAA2B,CAAC,EAC1C,cAAc,EACd,IAAI,EACJ,WAAW,EACX,aAAa,EACb,OAAO,EACP,WAAW,EACX,aAAa,GACd,EAAE;IACD,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,uCAAuC,EAAE,CAAA;IACvD,aAAa,EAAE,qBAAqB,CAAA;IACpC,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,mBAiDA"}
1
+ {"version":3,"file":"optimistically_create_message.d.ts","sourceRoot":"","sources":["../../../src/utils/cache/optimistically_create_message.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,qBAAqB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAEnF,OAAO,EAAE,uCAAuC,EAAE,MAAM,mEAAmE,CAAA;AAM3H,wBAAgB,2BAA2B,CAAC,EAC1C,cAAc,EACd,IAAI,EACJ,WAAW,EACX,aAAa,EACb,OAAO,EACP,WAAW,GACZ,EAAE;IACD,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,uCAAuC,EAAE,CAAA;IACvD,aAAa,EAAE,qBAAqB,CAAA;IACpC,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B,mBAgDA"}
@@ -9,8 +9,7 @@ export function optimisticallyCreateMessage({
9
9
  attachments,
10
10
  currentPerson,
11
11
  message,
12
- replyRootId,
13
- idempotentKey
12
+ replyRootId
14
13
  }) {
15
14
  const id = message?.id || generateTempMessageId();
16
15
 
@@ -40,8 +39,7 @@ export function optimisticallyCreateMessage({
40
39
  lastInGroup: true,
41
40
  pending: true,
42
41
  replyCount: 0,
43
- replyRootId: replyRootId || null,
44
- idempotentKey
42
+ replyRootId: replyRootId || null
45
43
  };
46
44
 
47
45
  // Add the optimistic message to the cache
@@ -1 +1 @@
1
- {"version":3,"file":"optimistically_create_message.js","names":["chatQueryClient","getMessagesQueryKey","convertAttachmentsForCreate","generatePlaceholderUlid","updateOrCreateRecordInPagesData","optimisticallyCreateMessage","conversationId","text","attachments","currentPerson","message","replyRootId","idempotentKey","id","generateTempMessageId","decoratedAttachments","optimisticMessage","type","messageType","html","createdAt","Date","toISOString","deletedAt","textEditedAt","mine","attachmentsForCreate","author","reactionCounts","renderAuthor","renderTime","myLatestInConversation","lastInGroup","pending","replyCount","queryKey","conversation_id","reply_root_id","setQueryData","data","record","offsetMs"],"sources":["../../../src/utils/cache/optimistically_create_message.ts"],"sourcesContent":["import { InfiniteData } from '@tanstack/react-query'\nimport { chatQueryClient } from '../../contexts/api_provider'\nimport { ApiCollection, CurrentPersonResource, MessageResource } from '../../types'\nimport { DenormalizedAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport { DenormalizedAttachmentResourceForCreate } from '../../types/resources/denormalized_attachment_resource_for_create'\nimport { getMessagesQueryKey } from '../../utils/request/get_messages'\nimport { convertAttachmentsForCreate } from '../convert_attachments_for_create'\nimport { generatePlaceholderUlid } from '../generate_placeholder_ulid'\nimport { updateOrCreateRecordInPagesData } from './page_mutations'\n\nexport function optimisticallyCreateMessage({\n conversationId,\n text,\n attachments,\n currentPerson,\n message,\n replyRootId,\n idempotentKey,\n}: {\n conversationId: number\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n currentPerson: CurrentPersonResource\n message?: MessageResource\n replyRootId?: string | null\n idempotentKey?: string\n}) {\n const id = message?.id || generateTempMessageId()\n\n // Convert attachments to denormalized format for optimistic UI\n const decoratedAttachments: DenormalizedAttachmentResource[] = convertAttachmentsForCreate(\n attachments || []\n )\n\n // Create an optimistic message\n const optimisticMessage: MessageResource = {\n ...message,\n type: 'Message',\n messageType: 'user',\n id,\n text,\n html: '', // Will be filled by server\n createdAt: new Date().toISOString(),\n deletedAt: null,\n textEditedAt: null,\n mine: true,\n attachments: decoratedAttachments,\n attachmentsForCreate: attachments || [],\n author: currentPerson,\n reactionCounts: [],\n renderAuthor: false,\n renderTime: true,\n myLatestInConversation: true,\n lastInGroup: true,\n pending: true,\n replyCount: 0,\n replyRootId: replyRootId || null,\n idempotentKey,\n }\n\n // Add the optimistic message to the cache\n type QueryData = InfiniteData<ApiCollection<MessageResource>>\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n updateOrCreateRecordInPagesData({\n data,\n record: optimisticMessage as MessageResource,\n })\n )\n\n return optimisticMessage\n}\n\nconst generateTempMessageId = () => {\n // Put it 5 seconds in the future to account for server lag of previously created messages\n // that are still pending. This gets overwritten by the server anyway.\n return `${generatePlaceholderUlid({ offsetMs: 5000 })}-temp`\n}\n"],"mappings":"AACA,SAASA,eAAe,QAAQ,6BAA6B;AAI7D,SAASC,mBAAmB,QAAQ,kCAAkC;AACtE,SAASC,2BAA2B,QAAQ,mCAAmC;AAC/E,SAASC,uBAAuB,QAAQ,8BAA8B;AACtE,SAASC,+BAA+B,QAAQ,kBAAkB;AAElE,OAAO,SAASC,2BAA2BA,CAAC;EAC1CC,cAAc;EACdC,IAAI;EACJC,WAAW;EACXC,aAAa;EACbC,OAAO;EACPC,WAAW;EACXC;AASF,CAAC,EAAE;EACD,MAAMC,EAAE,GAAGH,OAAO,EAAEG,EAAE,IAAIC,qBAAqB,CAAC,CAAC;;EAEjD;EACA,MAAMC,oBAAsD,GAAGb,2BAA2B,CACxFM,WAAW,IAAI,EACjB,CAAC;;EAED;EACA,MAAMQ,iBAAkC,GAAG;IACzC,GAAGN,OAAO;IACVO,IAAI,EAAE,SAAS;IACfC,WAAW,EAAE,MAAM;IACnBL,EAAE;IACFN,IAAI;IACJY,IAAI,EAAE,EAAE;IAAE;IACVC,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC;IACnCC,SAAS,EAAE,IAAI;IACfC,YAAY,EAAE,IAAI;IAClBC,IAAI,EAAE,IAAI;IACVjB,WAAW,EAAEO,oBAAoB;IACjCW,oBAAoB,EAAElB,WAAW,IAAI,EAAE;IACvCmB,MAAM,EAAElB,aAAa;IACrBmB,cAAc,EAAE,EAAE;IAClBC,YAAY,EAAE,KAAK;IACnBC,UAAU,EAAE,IAAI;IAChBC,sBAAsB,EAAE,IAAI;IAC5BC,WAAW,EAAE,IAAI;IACjBC,OAAO,EAAE,IAAI;IACbC,UAAU,EAAE,CAAC;IACbvB,WAAW,EAAEA,WAAW,IAAI,IAAI;IAChCC;EACF,CAAC;;EAED;;EAEA,MAAMuB,QAAQ,GAAGlC,mBAAmB,CAAC;IACnCmC,eAAe,EAAE9B,cAAc;IAC/B+B,aAAa,EAAE1B;EACjB,CAAC,CAAC;EAEFX,eAAe,CAACsC,YAAY,CAAYH,QAAQ,EAAEI,IAAI,IACpDnC,+BAA+B,CAAC;IAC9BmC,IAAI;IACJC,MAAM,EAAExB;EACV,CAAC,CACH,CAAC;EAED,OAAOA,iBAAiB;AAC1B;AAEA,MAAMF,qBAAqB,GAAGA,CAAA,KAAM;EAClC;EACA;EACA,OAAO,GAAGX,uBAAuB,CAAC;IAAEsC,QAAQ,EAAE;EAAK,CAAC,CAAC,OAAO;AAC9D,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"optimistically_create_message.js","names":["chatQueryClient","getMessagesQueryKey","convertAttachmentsForCreate","generatePlaceholderUlid","updateOrCreateRecordInPagesData","optimisticallyCreateMessage","conversationId","text","attachments","currentPerson","message","replyRootId","id","generateTempMessageId","decoratedAttachments","optimisticMessage","type","messageType","html","createdAt","Date","toISOString","deletedAt","textEditedAt","mine","attachmentsForCreate","author","reactionCounts","renderAuthor","renderTime","myLatestInConversation","lastInGroup","pending","replyCount","queryKey","conversation_id","reply_root_id","setQueryData","data","record","offsetMs"],"sources":["../../../src/utils/cache/optimistically_create_message.ts"],"sourcesContent":["import { InfiniteData } from '@tanstack/react-query'\nimport { chatQueryClient } from '../../contexts/api_provider'\nimport { ApiCollection, CurrentPersonResource, MessageResource } from '../../types'\nimport { DenormalizedAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport { DenormalizedAttachmentResourceForCreate } from '../../types/resources/denormalized_attachment_resource_for_create'\nimport { getMessagesQueryKey } from '../../utils/request/get_messages'\nimport { convertAttachmentsForCreate } from '../convert_attachments_for_create'\nimport { generatePlaceholderUlid } from '../generate_placeholder_ulid'\nimport { updateOrCreateRecordInPagesData } from './page_mutations'\n\nexport function optimisticallyCreateMessage({\n conversationId,\n text,\n attachments,\n currentPerson,\n message,\n replyRootId,\n}: {\n conversationId: number\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n currentPerson: CurrentPersonResource\n message?: MessageResource\n replyRootId?: string | null\n}) {\n const id = message?.id || generateTempMessageId()\n\n // Convert attachments to denormalized format for optimistic UI\n const decoratedAttachments: DenormalizedAttachmentResource[] = convertAttachmentsForCreate(\n attachments || []\n )\n\n // Create an optimistic message\n const optimisticMessage: MessageResource = {\n ...message,\n type: 'Message',\n messageType: 'user',\n id,\n text,\n html: '', // Will be filled by server\n createdAt: new Date().toISOString(),\n deletedAt: null,\n textEditedAt: null,\n mine: true,\n attachments: decoratedAttachments,\n attachmentsForCreate: attachments || [],\n author: currentPerson,\n reactionCounts: [],\n renderAuthor: false,\n renderTime: true,\n myLatestInConversation: true,\n lastInGroup: true,\n pending: true,\n replyCount: 0,\n replyRootId: replyRootId || null,\n }\n\n // Add the optimistic message to the cache\n type QueryData = InfiniteData<ApiCollection<MessageResource>>\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n updateOrCreateRecordInPagesData({\n data,\n record: optimisticMessage as MessageResource,\n })\n )\n\n return optimisticMessage\n}\n\nconst generateTempMessageId = () => {\n // Put it 5 seconds in the future to account for server lag of previously created messages\n // that are still pending. This gets overwritten by the server anyway.\n return `${generatePlaceholderUlid({ offsetMs: 5000 })}-temp`\n}\n"],"mappings":"AACA,SAASA,eAAe,QAAQ,6BAA6B;AAI7D,SAASC,mBAAmB,QAAQ,kCAAkC;AACtE,SAASC,2BAA2B,QAAQ,mCAAmC;AAC/E,SAASC,uBAAuB,QAAQ,8BAA8B;AACtE,SAASC,+BAA+B,QAAQ,kBAAkB;AAElE,OAAO,SAASC,2BAA2BA,CAAC;EAC1CC,cAAc;EACdC,IAAI;EACJC,WAAW;EACXC,aAAa;EACbC,OAAO;EACPC;AAQF,CAAC,EAAE;EACD,MAAMC,EAAE,GAAGF,OAAO,EAAEE,EAAE,IAAIC,qBAAqB,CAAC,CAAC;;EAEjD;EACA,MAAMC,oBAAsD,GAAGZ,2BAA2B,CACxFM,WAAW,IAAI,EACjB,CAAC;;EAED;EACA,MAAMO,iBAAkC,GAAG;IACzC,GAAGL,OAAO;IACVM,IAAI,EAAE,SAAS;IACfC,WAAW,EAAE,MAAM;IACnBL,EAAE;IACFL,IAAI;IACJW,IAAI,EAAE,EAAE;IAAE;IACVC,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC;IACnCC,SAAS,EAAE,IAAI;IACfC,YAAY,EAAE,IAAI;IAClBC,IAAI,EAAE,IAAI;IACVhB,WAAW,EAAEM,oBAAoB;IACjCW,oBAAoB,EAAEjB,WAAW,IAAI,EAAE;IACvCkB,MAAM,EAAEjB,aAAa;IACrBkB,cAAc,EAAE,EAAE;IAClBC,YAAY,EAAE,KAAK;IACnBC,UAAU,EAAE,IAAI;IAChBC,sBAAsB,EAAE,IAAI;IAC5BC,WAAW,EAAE,IAAI;IACjBC,OAAO,EAAE,IAAI;IACbC,UAAU,EAAE,CAAC;IACbtB,WAAW,EAAEA,WAAW,IAAI;EAC9B,CAAC;;EAED;;EAEA,MAAMuB,QAAQ,GAAGjC,mBAAmB,CAAC;IACnCkC,eAAe,EAAE7B,cAAc;IAC/B8B,aAAa,EAAEzB;EACjB,CAAC,CAAC;EAEFX,eAAe,CAACqC,YAAY,CAAYH,QAAQ,EAAEI,IAAI,IACpDlC,+BAA+B,CAAC;IAC9BkC,IAAI;IACJC,MAAM,EAAExB;EACV,CAAC,CACH,CAAC;EAED,OAAOA,iBAAiB;AAC1B;AAEA,MAAMF,qBAAqB,GAAGA,CAAA,KAAM;EAClC;EACA;EACA,OAAO,GAAGV,uBAAuB,CAAC;IAAEqC,QAAQ,EAAE;EAAK,CAAC,CAAC,OAAO;AAC9D,CAAC","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"transform_response.d.ts","sourceRoot":"","sources":["../../../src/utils/client/transform_response.ts"],"names":[],"mappings":"AAmGA,QAAA,MAAM,iBAAiB,yBAAyD,CAAA;AAEhF,eAAe,iBAAiB,CAAA"}
1
+ {"version":3,"file":"transform_response.d.ts","sourceRoot":"","sources":["../../../src/utils/client/transform_response.ts"],"names":[],"mappings":"AAiGA,QAAA,MAAM,iBAAiB,yBAAyD,CAAA;AAEhF,eAAe,iBAAiB,CAAA"}
@@ -36,25 +36,21 @@ const transformRelationships = relationships => {
36
36
  }
37
37
  }, {});
38
38
  };
39
- const addIncludedRecords = (record, included, seen, parent) => {
40
- const {
41
- relationships
42
- } = record;
39
+ const addIncludedRecords = (relationships, included, seen, parent) => {
43
40
  return Object.keys(relationships || {}).reduce((acc, key) => {
44
41
  const relationship = relationships[key];
45
42
  if (_.isArray(relationship.data)) {
46
43
  const records = _(relationship.data).map(elem => _.find(included, elem)).compact() // account for orphans
47
44
  .value();
48
- return _.set(acc, _.pluralize(key), _.map(records, related => transformRecord(related, included, seen)));
45
+ return _.set(acc, _.pluralize(key), _.map(records, record => transformRecord(record, included, seen)));
49
46
  } else {
50
47
  const [id, type] = _.at(relationship, ['data.id', 'data.type']);
51
48
  if (id && type) {
52
- const isSelfReference = id === record.id && type === record.type;
53
- const related = isSelfReference ? undefined : _.find(included, {
49
+ const record = _.find(included, {
54
50
  id,
55
51
  type
56
52
  });
57
- return _.set(acc, key, related ? transformRecord(related, included, seen) : null);
53
+ return _.set(acc, key, record ? transformRecord(record, included, seen) : null);
58
54
  } else {
59
55
  return acc;
60
56
  }
@@ -81,7 +77,7 @@ const transformRecord = (record, included, seen) => {
81
77
  ..._.mapKeys(attributes, (v, k) => k === 'length' ? `${type.charAt(0).toLowerCase()}${type.slice(1)}Length` : k, {})
82
78
  };
83
79
  seen.set(record, transformed);
84
- return addIncludedRecords(record, included, seen, transformed);
80
+ return addIncludedRecords(relationships, included, seen, transformed);
85
81
  }
86
82
  };
87
83
  const defaultTransformResponse = response => {
@@ -1 +1 @@
1
- {"version":3,"file":"transform_response.js","names":["_","inflection","keysToCamelCase","mixin","singular","plural","transformId","id","thru","parseInt","int","transformRelationships","relationships","Object","keys","reduce","acc","key","relationship","isArray","data","ids","map","singularize","get","type","addIncludedRecords","record","included","seen","parent","records","elem","find","compact","value","set","pluralize","related","transformRecord","at","isSelfReference","undefined","attributes","links","has","transformed","mapKeys","v","k","charAt","toLowerCase","slice","defaultTransformResponse","response","isEmpty","meta","WeakMap","result","d","transformResponse","flowRight"],"sources":["../../../src/utils/client/transform_response.ts"],"sourcesContent":["// @ts-nocheck\n// TODO: Fix this file but write tests first\n\nimport _ from 'lodash'\nimport inflection from 'lodash-inflection/lib/lodash-inflection'\nimport { keysToCamelCase } from './utils'\n\n_.mixin({ ...inflection })\n\n// Teach some bad grammar\n_.singular(/^(media)$/i, '$1')\n_.plural(/^(media)$/i, '$1')\n\n// eslint-disable-next-line eqeqeq\nconst transformId = id => _.thru(parseInt(id, 10), int => (int == id ? int : id))\n\nconst transformRelationships = relationships => {\n return Object.keys(relationships || {}).reduce((acc, key) => {\n const relationship = relationships[key]\n if (_.isArray(relationship.data)) {\n const ids = _.map(relationship.data, ({ id }) => transformId(id))\n return { ...acc, [`${_.singularize(key)}_ids`]: ids }\n } else {\n const id = _.get(relationship, 'data.id')\n const type = _.get(relationship, 'data.type', null)\n return {\n ...acc,\n [`${key}_id`]: id ? transformId(id) : null,\n [`${key}_type`]: type,\n }\n }\n }, {})\n}\n\nconst addIncludedRecords = (record, included, seen, parent) => {\n const { relationships } = record\n return Object.keys(relationships || {}).reduce((acc, key) => {\n const relationship = relationships[key]\n if (_.isArray(relationship.data)) {\n const records = _(relationship.data)\n .map(elem => _.find(included, elem))\n .compact() // account for orphans\n .value()\n return _.set(\n acc,\n _.pluralize(key),\n _.map(records, related => transformRecord(related, included, seen))\n )\n } else {\n const [id, type] = _.at(relationship, ['data.id', 'data.type'])\n if (id && type) {\n const isSelfReference = id === record.id && type === record.type\n const related = isSelfReference ? undefined : _.find(included, { id, type })\n return _.set(acc, key, related ? transformRecord(related, included, seen) : null)\n } else {\n return acc\n }\n }\n }, parent)\n}\n\nconst transformRecord = (record, included, seen) => {\n if (!record) return record\n const { id, attributes, links, relationships, type } = record\n\n if (seen.has(record)) {\n return seen.get(record)\n } else {\n const transformed = {\n id: transformId(id),\n type,\n links,\n ...transformRelationships(relationships),\n ..._.mapKeys(\n attributes,\n (v, k) => (k === 'length' ? `${type.charAt(0).toLowerCase()}${type.slice(1)}Length` : k),\n {}\n ),\n }\n\n seen.set(record, transformed)\n\n return addIncludedRecords(record, included, seen, transformed)\n }\n}\n\nconst defaultTransformResponse = response => {\n if (_.isEmpty(response)) return response\n const { data, included, meta, links } = response\n const seen = new WeakMap()\n\n if (_.isArray(data)) {\n const result = data.map(d => transformRecord(d, included, seen))\n return { data: result, meta, links, ...data }\n } else {\n return { data: { ...transformRecord(data, included, seen) }, meta, links }\n }\n}\n\nconst transformResponse = _.flowRight(keysToCamelCase, defaultTransformResponse)\n\nexport default transformResponse\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"transform_response.js","names":["_","inflection","keysToCamelCase","mixin","singular","plural","transformId","id","thru","parseInt","int","transformRelationships","relationships","Object","keys","reduce","acc","key","relationship","isArray","data","ids","map","singularize","get","type","addIncludedRecords","included","seen","parent","records","elem","find","compact","value","set","pluralize","record","transformRecord","at","attributes","links","has","transformed","mapKeys","v","k","charAt","toLowerCase","slice","defaultTransformResponse","response","isEmpty","meta","WeakMap","result","d","transformResponse","flowRight"],"sources":["../../../src/utils/client/transform_response.ts"],"sourcesContent":["// @ts-nocheck\n// TODO: Fix this file but write tests first\n\nimport _ from 'lodash'\nimport inflection from 'lodash-inflection/lib/lodash-inflection'\nimport { keysToCamelCase } from './utils'\n\n_.mixin({ ...inflection })\n\n// Teach some bad grammar\n_.singular(/^(media)$/i, '$1')\n_.plural(/^(media)$/i, '$1')\n\n// eslint-disable-next-line eqeqeq\nconst transformId = id => _.thru(parseInt(id, 10), int => (int == id ? int : id))\n\nconst transformRelationships = relationships => {\n return Object.keys(relationships || {}).reduce((acc, key) => {\n const relationship = relationships[key]\n if (_.isArray(relationship.data)) {\n const ids = _.map(relationship.data, ({ id }) => transformId(id))\n return { ...acc, [`${_.singularize(key)}_ids`]: ids }\n } else {\n const id = _.get(relationship, 'data.id')\n const type = _.get(relationship, 'data.type', null)\n return {\n ...acc,\n [`${key}_id`]: id ? transformId(id) : null,\n [`${key}_type`]: type,\n }\n }\n }, {})\n}\n\nconst addIncludedRecords = (relationships, included, seen, parent) => {\n return Object.keys(relationships || {}).reduce((acc, key) => {\n const relationship = relationships[key]\n if (_.isArray(relationship.data)) {\n const records = _(relationship.data)\n .map(elem => _.find(included, elem))\n .compact() // account for orphans\n .value()\n return _.set(\n acc,\n _.pluralize(key),\n _.map(records, record => transformRecord(record, included, seen))\n )\n } else {\n const [id, type] = _.at(relationship, ['data.id', 'data.type'])\n if (id && type) {\n const record = _.find(included, { id, type })\n return _.set(acc, key, record ? transformRecord(record, included, seen) : null)\n } else {\n return acc\n }\n }\n }, parent)\n}\n\nconst transformRecord = (record, included, seen) => {\n if (!record) return record\n const { id, attributes, links, relationships, type } = record\n\n if (seen.has(record)) {\n return seen.get(record)\n } else {\n const transformed = {\n id: transformId(id),\n type,\n links,\n ...transformRelationships(relationships),\n ..._.mapKeys(\n attributes,\n (v, k) => (k === 'length' ? `${type.charAt(0).toLowerCase()}${type.slice(1)}Length` : k),\n {}\n ),\n }\n\n seen.set(record, transformed)\n\n return addIncludedRecords(relationships, included, seen, transformed)\n }\n}\n\nconst defaultTransformResponse = response => {\n if (_.isEmpty(response)) return response\n const { data, included, meta, links } = response\n const seen = new WeakMap()\n\n if (_.isArray(data)) {\n const result = data.map(d => transformRecord(d, included, seen))\n return { data: result, meta, links, ...data }\n } else {\n return { data: { ...transformRecord(data, included, seen) }, meta, links }\n }\n}\n\nconst transformResponse = _.flowRight(keysToCamelCase, defaultTransformResponse)\n\nexport default transformResponse\n"],"mappings":"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","ignoreList":[]}
@@ -8,7 +8,6 @@ export type ReplyShadowMessage = {
8
8
  type: 'ReplyShadowMessage';
9
9
  id: string;
10
10
  messageId: string;
11
- replyRoot: MessageResource | null;
12
11
  isReplyShadowMessage: boolean;
13
12
  nextRendersAuthor: boolean;
14
13
  };
@@ -1 +1 @@
1
- {"version":3,"file":"group_messages.d.ts","sourceRoot":"","sources":["../../src/utils/group_messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAMjE,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,oBAAoB,CAAA;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,eAAe,GAAG,IAAI,CAAA;IACjC,oBAAoB,EAAE,OAAO,CAAA;IAC7B,iBAAiB,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,aAAa,GAAG,kBAAkB,CAAA;AAElF,UAAU,kBAAkB;IAC1B,EAAE,EAAE,eAAe,EAAE,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,kBAAkB,GAAG,eAAe,EAAE,CAyC1F"}
1
+ {"version":3,"file":"group_messages.d.ts","sourceRoot":"","sources":["../../src/utils/group_messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAMjE,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,oBAAoB,CAAA;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,oBAAoB,EAAE,OAAO,CAAA;IAC7B,iBAAiB,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,aAAa,GAAG,kBAAkB,CAAA;AAElF,UAAU,kBAAkB;IAC1B,EAAE,EAAE,eAAe,EAAE,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,kBAAkB,GAAG,eAAe,EAAE,CAkC1F"}
@@ -6,7 +6,6 @@ export function groupMessages({
6
6
  inReplyScreen
7
7
  }) {
8
8
  const items = [];
9
- const messagesById = new Map(ms.map(message => [message.id, message]));
10
9
  let myLatestSeen = false;
11
10
  let nextNeighborEnriched;
12
11
  ms.forEach((message, i) => {
@@ -23,10 +22,7 @@ export function groupMessages({
23
22
  }
24
23
  const isMyLatest = !myLatestSeen && message.mine;
25
24
  if (isMyLatest) myLatestSeen = true;
26
- const enriched = enrichRegularMessage({
27
- ...message,
28
- replyRoot: resolveReplyRoot(message, messagesById)
29
- }, prev, next, isMyLatest, !!inReplyScreen);
25
+ const enriched = enrichRegularMessage(message, prev, next, isMyLatest, !!inReplyScreen);
30
26
  items.push(enriched);
31
27
  const shadow = replyShadowFor(enriched, prev);
32
28
  if (shadow) items.push(shadow);
@@ -43,10 +39,6 @@ function neighborsOf(arr, i) {
43
39
  next: arr[i - 1]
44
40
  };
45
41
  }
46
- function resolveReplyRoot(message, messagesById) {
47
- if (!message.replyRootId || message.replyRootId === message.id) return null;
48
- return messagesById.get(message.replyRootId) ?? message.replyRoot ?? null;
49
- }
50
42
  function enrichSystemMessage(message, next) {
51
43
  return {
52
44
  ...message,
@@ -122,7 +114,6 @@ function replyShadowFor(message, prev) {
122
114
  type: 'ReplyShadowMessage',
123
115
  id: `${message.id}-${message.replyRootId}`,
124
116
  messageId: message.replyRootId,
125
- replyRoot: message.replyRoot ?? null,
126
117
  isReplyShadowMessage: true,
127
118
  nextRendersAuthor: message.renderAuthor ?? false
128
119
  };
@@ -1 +1 @@
1
- {"version":3,"file":"group_messages.js","names":["dayjs","isSystemMessage","FIVE_MINUTES_MS","groupMessages","ms","inReplyScreen","items","messagesById","Map","map","message","id","myLatestSeen","nextNeighborEnriched","forEach","i","prev","neighborsOf","next","enriched","enrichSystemMessage","push","datesDifferBetween","dateSeparator","isMyLatest","mine","enrichRegularMessage","replyRoot","resolveReplyRoot","shadow","replyShadowFor","arr","replyRootId","get","myLatestInConversation","lastInGroup","renderAuthor","nextRendersAuthor","isReplyShadowMessage","nextIsReplyShadowMessage","threadPosition","inThread","showThreadDetails","startsNewGroup","nextIntroducesReplyShadow","threadPositionFor","prevIsMyReply","undefined","nextIsMyReply","a","b","author","differsByMoreThan5Min","Math","abs","toMillis","createdAt","iso","Date","getTime","dateKey","format","type","date","isThreadRoot","isLast","current","nextInThread","nextIsThreadRoot","differentThread","enteringNewThread","messageId"],"sources":["../../src/utils/group_messages.ts"],"sourcesContent":["import type { MessageResource } from '../types/resources/message'\nimport dayjs from './dayjs'\nimport { isSystemMessage } from './system_messages'\n\nconst FIVE_MINUTES_MS = 5 * 60 * 1000\n\nexport type DateSeparator = { type: 'DateSeparator'; id: string; date: string }\n\nexport type ReplyShadowMessage = {\n type: 'ReplyShadowMessage'\n id: string\n messageId: string\n replyRoot: MessageResource | null\n isReplyShadowMessage: boolean\n nextRendersAuthor: boolean\n}\n\nexport type EnrichedMessage = MessageResource | DateSeparator | ReplyShadowMessage\n\ninterface GroupMessagesProps {\n ms: MessageResource[]\n inReplyScreen?: boolean\n}\n\nexport function groupMessages({ ms, inReplyScreen }: GroupMessagesProps): EnrichedMessage[] {\n const items: EnrichedMessage[] = []\n const messagesById = new Map(ms.map(message => [message.id, message]))\n let myLatestSeen = false\n let nextNeighborEnriched: MessageResource | undefined\n\n ms.forEach((message, i) => {\n const { prev } = neighborsOf(ms, i)\n const next = nextNeighborEnriched\n\n if (isSystemMessage(message)) {\n const enriched = enrichSystemMessage(message, next)\n items.push(enriched)\n if (datesDifferBetween(message, prev)) items.push(dateSeparator(message))\n nextNeighborEnriched = enriched\n return\n }\n\n const isMyLatest = !myLatestSeen && message.mine\n if (isMyLatest) myLatestSeen = true\n\n const enriched = enrichRegularMessage(\n { ...message, replyRoot: resolveReplyRoot(message, messagesById) },\n prev,\n next,\n isMyLatest,\n !!inReplyScreen\n )\n items.push(enriched)\n\n const shadow = replyShadowFor(enriched, prev)\n if (shadow) items.push(shadow)\n\n if (!prev || datesDifferBetween(message, prev)) {\n items.push(dateSeparator(message))\n }\n\n nextNeighborEnriched = enriched\n })\n\n return items\n}\n\nfunction neighborsOf<T>(arr: T[], i: number): { prev: T | undefined; next: T | undefined } {\n return { prev: arr[i + 1], next: arr[i - 1] }\n}\n\nfunction resolveReplyRoot(\n message: MessageResource,\n messagesById: Map<string, MessageResource>\n): MessageResource | null {\n if (!message.replyRootId || message.replyRootId === message.id) return null\n return messagesById.get(message.replyRootId) ?? message.replyRoot ?? null\n}\n\nfunction enrichSystemMessage(\n message: MessageResource,\n next: MessageResource | undefined\n): MessageResource {\n return {\n ...message,\n myLatestInConversation: false,\n lastInGroup: true,\n renderAuthor: false,\n nextRendersAuthor: next?.renderAuthor,\n isReplyShadowMessage: false,\n nextIsReplyShadowMessage: false,\n threadPosition: null,\n }\n}\n\nfunction enrichRegularMessage(\n message: MessageResource,\n prev: MessageResource | undefined,\n next: MessageResource | undefined,\n isMyLatest: boolean,\n inReplyScreen: boolean\n): MessageResource {\n const inThread = message.replyRootId !== null\n const showThreadDetails = !inReplyScreen && inThread\n\n return {\n ...message,\n myLatestInConversation: isMyLatest,\n lastInGroup: !next || startsNewGroup(next, message),\n renderAuthor: !message.mine && (!prev || startsNewGroup(message, prev)),\n nextRendersAuthor: next?.renderAuthor,\n isReplyShadowMessage: false,\n nextIsReplyShadowMessage: nextIntroducesReplyShadow(next, message),\n threadPosition: showThreadDetails ? threadPositionFor(message, next) : null,\n prevIsMyReply: showThreadDetails ? prev?.mine : undefined,\n nextIsMyReply: showThreadDetails ? next?.mine : undefined,\n }\n}\n\nfunction startsNewGroup(a: MessageResource, b: MessageResource): boolean {\n return (\n a.author?.id !== b.author?.id ||\n differsByMoreThan5Min(a, b) ||\n a.replyRootId !== b.replyRootId ||\n datesDifferBetween(a, b)\n )\n}\n\nfunction differsByMoreThan5Min(a: MessageResource, b: MessageResource): boolean {\n return Math.abs(toMillis(a.createdAt) - toMillis(b.createdAt)) > FIVE_MINUTES_MS\n}\n\nfunction toMillis(iso: string): number {\n return new Date(iso).getTime()\n}\n\nfunction datesDifferBetween(a: MessageResource, b: MessageResource | undefined): boolean {\n if (!b) return false\n return dateKey(a) !== dateKey(b)\n}\n\nfunction dateKey(message: MessageResource): string {\n return dayjs(message.createdAt).format('YYYY-MM-DD')\n}\n\nfunction dateSeparator(message: MessageResource): DateSeparator {\n return { type: 'DateSeparator', id: `day-divider-${message.id}`, date: dateKey(message) }\n}\n\nfunction threadPositionFor(\n message: MessageResource,\n next: MessageResource | undefined\n): 'first' | 'center' | 'last' | null {\n const isThreadRoot = message.replyRootId === message.id\n const isLast =\n !next || next.replyRootId !== message.replyRootId || datesDifferBetween(next, message)\n\n if (isThreadRoot && isLast) return null\n if (isThreadRoot) return 'first'\n if (isLast) return 'last'\n return 'center'\n}\n\nfunction nextIntroducesReplyShadow(\n next: MessageResource | undefined,\n current: MessageResource\n): boolean {\n if (!next) return false\n const nextInThread = next.replyRootId !== null\n const nextIsThreadRoot = next.replyRootId === next.id\n const differentThread = next.replyRootId !== current.replyRootId\n return nextInThread && !nextIsThreadRoot && (differentThread || datesDifferBetween(next, current))\n}\n\nfunction replyShadowFor(\n message: MessageResource,\n prev: MessageResource | undefined\n): ReplyShadowMessage | undefined {\n if (!message.replyRootId) return undefined\n if (message.replyRootId === message.id) return undefined\n\n const enteringNewThread =\n !prev || prev.replyRootId !== message.replyRootId || datesDifferBetween(prev, message)\n if (!enteringNewThread) return undefined\n\n return {\n type: 'ReplyShadowMessage',\n id: `${message.id}-${message.replyRootId}`,\n messageId: message.replyRootId,\n replyRoot: message.replyRoot ?? null,\n isReplyShadowMessage: true,\n nextRendersAuthor: message.renderAuthor ?? false,\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"group_messages.js","names":["dayjs","isSystemMessage","FIVE_MINUTES_MS","groupMessages","ms","inReplyScreen","items","myLatestSeen","nextNeighborEnriched","forEach","message","i","prev","neighborsOf","next","enriched","enrichSystemMessage","push","datesDifferBetween","dateSeparator","isMyLatest","mine","enrichRegularMessage","shadow","replyShadowFor","arr","myLatestInConversation","lastInGroup","renderAuthor","nextRendersAuthor","isReplyShadowMessage","nextIsReplyShadowMessage","threadPosition","inThread","replyRootId","showThreadDetails","startsNewGroup","nextIntroducesReplyShadow","threadPositionFor","prevIsMyReply","undefined","nextIsMyReply","a","b","author","id","differsByMoreThan5Min","Math","abs","toMillis","createdAt","iso","Date","getTime","dateKey","format","type","date","isThreadRoot","isLast","current","nextInThread","nextIsThreadRoot","differentThread","enteringNewThread","messageId"],"sources":["../../src/utils/group_messages.ts"],"sourcesContent":["import type { MessageResource } from '../types/resources/message'\nimport dayjs from './dayjs'\nimport { isSystemMessage } from './system_messages'\n\nconst FIVE_MINUTES_MS = 5 * 60 * 1000\n\nexport type DateSeparator = { type: 'DateSeparator'; id: string; date: string }\n\nexport type ReplyShadowMessage = {\n type: 'ReplyShadowMessage'\n id: string\n messageId: string\n isReplyShadowMessage: boolean\n nextRendersAuthor: boolean\n}\n\nexport type EnrichedMessage = MessageResource | DateSeparator | ReplyShadowMessage\n\ninterface GroupMessagesProps {\n ms: MessageResource[]\n inReplyScreen?: boolean\n}\n\nexport function groupMessages({ ms, inReplyScreen }: GroupMessagesProps): EnrichedMessage[] {\n const items: EnrichedMessage[] = []\n let myLatestSeen = false\n let nextNeighborEnriched: MessageResource | undefined\n\n ms.forEach((message, i) => {\n const { prev } = neighborsOf(ms, i)\n const next = nextNeighborEnriched\n\n if (isSystemMessage(message)) {\n const enriched = enrichSystemMessage(message, next)\n items.push(enriched)\n if (datesDifferBetween(message, prev)) items.push(dateSeparator(message))\n nextNeighborEnriched = enriched\n return\n }\n\n const isMyLatest = !myLatestSeen && message.mine\n if (isMyLatest) myLatestSeen = true\n\n const enriched = enrichRegularMessage(message, prev, next, isMyLatest, !!inReplyScreen)\n items.push(enriched)\n\n const shadow = replyShadowFor(enriched, prev)\n if (shadow) items.push(shadow)\n\n if (!prev || datesDifferBetween(message, prev)) {\n items.push(dateSeparator(message))\n }\n\n nextNeighborEnriched = enriched\n })\n\n return items\n}\n\nfunction neighborsOf<T>(arr: T[], i: number): { prev: T | undefined; next: T | undefined } {\n return { prev: arr[i + 1], next: arr[i - 1] }\n}\n\nfunction enrichSystemMessage(\n message: MessageResource,\n next: MessageResource | undefined\n): MessageResource {\n return {\n ...message,\n myLatestInConversation: false,\n lastInGroup: true,\n renderAuthor: false,\n nextRendersAuthor: next?.renderAuthor,\n isReplyShadowMessage: false,\n nextIsReplyShadowMessage: false,\n threadPosition: null,\n }\n}\n\nfunction enrichRegularMessage(\n message: MessageResource,\n prev: MessageResource | undefined,\n next: MessageResource | undefined,\n isMyLatest: boolean,\n inReplyScreen: boolean\n): MessageResource {\n const inThread = message.replyRootId !== null\n const showThreadDetails = !inReplyScreen && inThread\n\n return {\n ...message,\n myLatestInConversation: isMyLatest,\n lastInGroup: !next || startsNewGroup(next, message),\n renderAuthor: !message.mine && (!prev || startsNewGroup(message, prev)),\n nextRendersAuthor: next?.renderAuthor,\n isReplyShadowMessage: false,\n nextIsReplyShadowMessage: nextIntroducesReplyShadow(next, message),\n threadPosition: showThreadDetails ? threadPositionFor(message, next) : null,\n prevIsMyReply: showThreadDetails ? prev?.mine : undefined,\n nextIsMyReply: showThreadDetails ? next?.mine : undefined,\n }\n}\n\nfunction startsNewGroup(a: MessageResource, b: MessageResource): boolean {\n return (\n a.author?.id !== b.author?.id ||\n differsByMoreThan5Min(a, b) ||\n a.replyRootId !== b.replyRootId ||\n datesDifferBetween(a, b)\n )\n}\n\nfunction differsByMoreThan5Min(a: MessageResource, b: MessageResource): boolean {\n return Math.abs(toMillis(a.createdAt) - toMillis(b.createdAt)) > FIVE_MINUTES_MS\n}\n\nfunction toMillis(iso: string): number {\n return new Date(iso).getTime()\n}\n\nfunction datesDifferBetween(a: MessageResource, b: MessageResource | undefined): boolean {\n if (!b) return false\n return dateKey(a) !== dateKey(b)\n}\n\nfunction dateKey(message: MessageResource): string {\n return dayjs(message.createdAt).format('YYYY-MM-DD')\n}\n\nfunction dateSeparator(message: MessageResource): DateSeparator {\n return { type: 'DateSeparator', id: `day-divider-${message.id}`, date: dateKey(message) }\n}\n\nfunction threadPositionFor(\n message: MessageResource,\n next: MessageResource | undefined\n): 'first' | 'center' | 'last' | null {\n const isThreadRoot = message.replyRootId === message.id\n const isLast =\n !next || next.replyRootId !== message.replyRootId || datesDifferBetween(next, message)\n\n if (isThreadRoot && isLast) return null\n if (isThreadRoot) return 'first'\n if (isLast) return 'last'\n return 'center'\n}\n\nfunction nextIntroducesReplyShadow(\n next: MessageResource | undefined,\n current: MessageResource\n): boolean {\n if (!next) return false\n const nextInThread = next.replyRootId !== null\n const nextIsThreadRoot = next.replyRootId === next.id\n const differentThread = next.replyRootId !== current.replyRootId\n return nextInThread && !nextIsThreadRoot && (differentThread || datesDifferBetween(next, current))\n}\n\nfunction replyShadowFor(\n message: MessageResource,\n prev: MessageResource | undefined\n): ReplyShadowMessage | undefined {\n if (!message.replyRootId) return undefined\n if (message.replyRootId === message.id) return undefined\n\n const enteringNewThread =\n !prev || prev.replyRootId !== message.replyRootId || datesDifferBetween(prev, message)\n if (!enteringNewThread) return undefined\n\n return {\n type: 'ReplyShadowMessage',\n id: `${message.id}-${message.replyRootId}`,\n messageId: message.replyRootId,\n isReplyShadowMessage: true,\n nextRendersAuthor: message.renderAuthor ?? false,\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"transform_message_event_data_to_message_resource.d.ts","sourceRoot":"","sources":["../../../src/utils/jolt/transform_message_event_data_to_message_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAA;AAI5E,wBAAgB,0CAA0C,CAAC,EACzD,IAAI,EACJ,eAAe,GAChB,EAAE;IACD,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;IACzC,eAAe,EAAE,MAAM,CAAA;CACxB,GAAG,eAAe,CA+BlB"}
1
+ {"version":3,"file":"transform_message_event_data_to_message_resource.d.ts","sourceRoot":"","sources":["../../../src/utils/jolt/transform_message_event_data_to_message_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAA;AAI5E,wBAAgB,0CAA0C,CAAC,EACzD,IAAI,EACJ,eAAe,GAChB,EAAE;IACD,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;IACzC,eAAe,EAAE,MAAM,CAAA;CACxB,GAAG,eAAe,CA8BlB"}
@@ -22,7 +22,6 @@ export function transformMessageEventDataToMessageResource({
22
22
  reactionCounts: [],
23
23
  replyCount: data.reply_count || 0,
24
24
  replyRootId: data.reply_root_id || null,
25
- idempotentKey: data.idempotent_key ?? null,
26
25
  messageType: data.message_type,
27
26
  personIdsForSystemEvent: data.system_event_person_ids,
28
27
  systemTextParts: data.system_text_parts ? {
@@ -1 +1 @@
1
- {"version":3,"file":"transform_message_event_data_to_message_resource.js","names":["deepCamelCaseKeys","transformMessageEventDataToMessageResource","data","currentPersonId","type","id","sort_key","text","html","createdAt","created_at","deletedAt","deleted_at","textEditedAt","text_edited_at","mine","author_id","attachments","author","name","author_name","avatar","author_avatar","reactionCounts","replyCount","reply_count","replyRootId","reply_root_id","idempotentKey","idempotent_key","messageType","message_type","personIdsForSystemEvent","system_event_person_ids","systemTextParts","system_text_parts","names","overflowCount","overflow_count","action"],"sources":["../../../src/utils/jolt/transform_message_event_data_to_message_resource.ts"],"sourcesContent":["import { MessageResource } from '../../types'\nimport { MessageCreatedEvent } from '../../types/jolt_events/message_events'\nimport { DenormalizedAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport { deepCamelCaseKeys } from '../deepCamelCaseKeys'\n\nexport function transformMessageEventDataToMessageResource({\n data,\n currentPersonId,\n}: {\n data: MessageCreatedEvent['data']['data']\n currentPersonId: number\n}): MessageResource {\n return {\n type: 'Message',\n id: data.sort_key,\n text: data.text,\n html: data.html,\n createdAt: data.created_at,\n deletedAt: data.deleted_at,\n textEditedAt: data.text_edited_at,\n mine: data.author_id === currentPersonId,\n attachments: deepCamelCaseKeys<DenormalizedAttachmentResource[]>(data.attachments) || [],\n author: {\n type: 'Person',\n id: data.author_id,\n name: data.author_name,\n avatar: data.author_avatar,\n },\n reactionCounts: [],\n replyCount: data.reply_count || 0,\n replyRootId: data.reply_root_id || null,\n idempotentKey: data.idempotent_key ?? null,\n messageType: data.message_type,\n personIdsForSystemEvent: data.system_event_person_ids,\n systemTextParts: data.system_text_parts\n ? {\n names: data.system_text_parts.names,\n overflowCount: data.system_text_parts.overflow_count,\n action: data.system_text_parts.action,\n }\n : null,\n }\n}\n"],"mappings":"AAGA,SAASA,iBAAiB,QAAQ,sBAAsB;AAExD,OAAO,SAASC,0CAA0CA,CAAC;EACzDC,IAAI;EACJC;AAIF,CAAC,EAAmB;EAClB,OAAO;IACLC,IAAI,EAAE,SAAS;IACfC,EAAE,EAAEH,IAAI,CAACI,QAAQ;IACjBC,IAAI,EAAEL,IAAI,CAACK,IAAI;IACfC,IAAI,EAAEN,IAAI,CAACM,IAAI;IACfC,SAAS,EAAEP,IAAI,CAACQ,UAAU;IAC1BC,SAAS,EAAET,IAAI,CAACU,UAAU;IAC1BC,YAAY,EAAEX,IAAI,CAACY,cAAc;IACjCC,IAAI,EAAEb,IAAI,CAACc,SAAS,KAAKb,eAAe;IACxCc,WAAW,EAAEjB,iBAAiB,CAAmCE,IAAI,CAACe,WAAW,CAAC,IAAI,EAAE;IACxFC,MAAM,EAAE;MACNd,IAAI,EAAE,QAAQ;MACdC,EAAE,EAAEH,IAAI,CAACc,SAAS;MAClBG,IAAI,EAAEjB,IAAI,CAACkB,WAAW;MACtBC,MAAM,EAAEnB,IAAI,CAACoB;IACf,CAAC;IACDC,cAAc,EAAE,EAAE;IAClBC,UAAU,EAAEtB,IAAI,CAACuB,WAAW,IAAI,CAAC;IACjCC,WAAW,EAAExB,IAAI,CAACyB,aAAa,IAAI,IAAI;IACvCC,aAAa,EAAE1B,IAAI,CAAC2B,cAAc,IAAI,IAAI;IAC1CC,WAAW,EAAE5B,IAAI,CAAC6B,YAAY;IAC9BC,uBAAuB,EAAE9B,IAAI,CAAC+B,uBAAuB;IACrDC,eAAe,EAAEhC,IAAI,CAACiC,iBAAiB,GACnC;MACEC,KAAK,EAAElC,IAAI,CAACiC,iBAAiB,CAACC,KAAK;MACnCC,aAAa,EAAEnC,IAAI,CAACiC,iBAAiB,CAACG,cAAc;MACpDC,MAAM,EAAErC,IAAI,CAACiC,iBAAiB,CAACI;IACjC,CAAC,GACD;EACN,CAAC;AACH","ignoreList":[]}
1
+ {"version":3,"file":"transform_message_event_data_to_message_resource.js","names":["deepCamelCaseKeys","transformMessageEventDataToMessageResource","data","currentPersonId","type","id","sort_key","text","html","createdAt","created_at","deletedAt","deleted_at","textEditedAt","text_edited_at","mine","author_id","attachments","author","name","author_name","avatar","author_avatar","reactionCounts","replyCount","reply_count","replyRootId","reply_root_id","messageType","message_type","personIdsForSystemEvent","system_event_person_ids","systemTextParts","system_text_parts","names","overflowCount","overflow_count","action"],"sources":["../../../src/utils/jolt/transform_message_event_data_to_message_resource.ts"],"sourcesContent":["import { MessageResource } from '../../types'\nimport { MessageCreatedEvent } from '../../types/jolt_events/message_events'\nimport { DenormalizedAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport { deepCamelCaseKeys } from '../deepCamelCaseKeys'\n\nexport function transformMessageEventDataToMessageResource({\n data,\n currentPersonId,\n}: {\n data: MessageCreatedEvent['data']['data']\n currentPersonId: number\n}): MessageResource {\n return {\n type: 'Message',\n id: data.sort_key,\n text: data.text,\n html: data.html,\n createdAt: data.created_at,\n deletedAt: data.deleted_at,\n textEditedAt: data.text_edited_at,\n mine: data.author_id === currentPersonId,\n attachments: deepCamelCaseKeys<DenormalizedAttachmentResource[]>(data.attachments) || [],\n author: {\n type: 'Person',\n id: data.author_id,\n name: data.author_name,\n avatar: data.author_avatar,\n },\n reactionCounts: [],\n replyCount: data.reply_count || 0,\n replyRootId: data.reply_root_id || null,\n messageType: data.message_type,\n personIdsForSystemEvent: data.system_event_person_ids,\n systemTextParts: data.system_text_parts\n ? {\n names: data.system_text_parts.names,\n overflowCount: data.system_text_parts.overflow_count,\n action: data.system_text_parts.action,\n }\n : null,\n }\n}\n"],"mappings":"AAGA,SAASA,iBAAiB,QAAQ,sBAAsB;AAExD,OAAO,SAASC,0CAA0CA,CAAC;EACzDC,IAAI;EACJC;AAIF,CAAC,EAAmB;EAClB,OAAO;IACLC,IAAI,EAAE,SAAS;IACfC,EAAE,EAAEH,IAAI,CAACI,QAAQ;IACjBC,IAAI,EAAEL,IAAI,CAACK,IAAI;IACfC,IAAI,EAAEN,IAAI,CAACM,IAAI;IACfC,SAAS,EAAEP,IAAI,CAACQ,UAAU;IAC1BC,SAAS,EAAET,IAAI,CAACU,UAAU;IAC1BC,YAAY,EAAEX,IAAI,CAACY,cAAc;IACjCC,IAAI,EAAEb,IAAI,CAACc,SAAS,KAAKb,eAAe;IACxCc,WAAW,EAAEjB,iBAAiB,CAAmCE,IAAI,CAACe,WAAW,CAAC,IAAI,EAAE;IACxFC,MAAM,EAAE;MACNd,IAAI,EAAE,QAAQ;MACdC,EAAE,EAAEH,IAAI,CAACc,SAAS;MAClBG,IAAI,EAAEjB,IAAI,CAACkB,WAAW;MACtBC,MAAM,EAAEnB,IAAI,CAACoB;IACf,CAAC;IACDC,cAAc,EAAE,EAAE;IAClBC,UAAU,EAAEtB,IAAI,CAACuB,WAAW,IAAI,CAAC;IACjCC,WAAW,EAAExB,IAAI,CAACyB,aAAa,IAAI,IAAI;IACvCC,WAAW,EAAE1B,IAAI,CAAC2B,YAAY;IAC9BC,uBAAuB,EAAE5B,IAAI,CAAC6B,uBAAuB;IACrDC,eAAe,EAAE9B,IAAI,CAAC+B,iBAAiB,GACnC;MACEC,KAAK,EAAEhC,IAAI,CAAC+B,iBAAiB,CAACC,KAAK;MACnCC,aAAa,EAAEjC,IAAI,CAAC+B,iBAAiB,CAACG,cAAc;MACpDC,MAAM,EAAEnC,IAAI,CAAC+B,iBAAiB,CAACI;IACjC,CAAC,GACD;EACN,CAAC;AACH","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"messages_data_options.d.ts","sourceRoot":"","sources":["../../../src/utils/request/messages_data_options.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB;;;;CAmB5B,CAAA;AAED,eAAO,MAAM,kBAAkB,UAAmE,CAAA"}
1
+ {"version":3,"file":"messages_data_options.d.ts","sourceRoot":"","sources":["../../../src/utils/request/messages_data_options.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB;;;;CAkB5B,CAAA;AAED,eAAO,MAAM,kBAAkB,UAAgC,CAAA"}
@@ -1,7 +1,7 @@
1
1
  export const getMessageFields = {
2
- Message: ['text', 'text_edited_at', 'mine', 'attachments', 'created_at', 'deleted_at', 'author', 'reaction_counts', 'reply_count', 'reply_root', 'idempotent_key', 'message_type', 'person_ids_for_system_event', 'system_text_parts'],
2
+ Message: ['text', 'text_edited_at', 'mine', 'attachments', 'created_at', 'deleted_at', 'author', 'reaction_counts', 'reply_count', 'reply_root', 'message_type', 'person_ids_for_system_event', 'system_text_parts'],
3
3
  Person: ['name', 'avatar'],
4
4
  ReactionCount: ['value', 'count', 'mine', 'message_id', 'author_ids']
5
5
  };
6
- export const getMessagesInclude = ['author', 'reaction_counts', 'reply_root', 'reply_root.author'];
6
+ export const getMessagesInclude = ['author', 'reaction_counts'];
7
7
  //# sourceMappingURL=messages_data_options.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages_data_options.js","names":["getMessageFields","Message","Person","ReactionCount","getMessagesInclude"],"sources":["../../../src/utils/request/messages_data_options.ts"],"sourcesContent":["export const getMessageFields = {\n Message: [\n 'text',\n 'text_edited_at',\n 'mine',\n 'attachments',\n 'created_at',\n 'deleted_at',\n 'author',\n 'reaction_counts',\n 'reply_count',\n 'reply_root',\n 'idempotent_key',\n 'message_type',\n 'person_ids_for_system_event',\n 'system_text_parts',\n ],\n Person: ['name', 'avatar'],\n ReactionCount: ['value', 'count', 'mine', 'message_id', 'author_ids'],\n}\n\nexport const getMessagesInclude = ['author', 'reaction_counts', 'reply_root', 'reply_root.author']\n"],"mappings":"AAAA,OAAO,MAAMA,gBAAgB,GAAG;EAC9BC,OAAO,EAAE,CACP,MAAM,EACN,gBAAgB,EAChB,MAAM,EACN,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,6BAA6B,EAC7B,mBAAmB,CACpB;EACDC,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;EAC1BC,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY;AACtE,CAAC;AAED,OAAO,MAAMC,kBAAkB,GAAG,CAAC,QAAQ,EAAE,iBAAiB,EAAE,YAAY,EAAE,mBAAmB,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"messages_data_options.js","names":["getMessageFields","Message","Person","ReactionCount","getMessagesInclude"],"sources":["../../../src/utils/request/messages_data_options.ts"],"sourcesContent":["export const getMessageFields = {\n Message: [\n 'text',\n 'text_edited_at',\n 'mine',\n 'attachments',\n 'created_at',\n 'deleted_at',\n 'author',\n 'reaction_counts',\n 'reply_count',\n 'reply_root',\n 'message_type',\n 'person_ids_for_system_event',\n 'system_text_parts',\n ],\n Person: ['name', 'avatar'],\n ReactionCount: ['value', 'count', 'mine', 'message_id', 'author_ids'],\n}\n\nexport const getMessagesInclude = ['author', 'reaction_counts']\n"],"mappings":"AAAA,OAAO,MAAMA,gBAAgB,GAAG;EAC9BC,OAAO,EAAE,CACP,MAAM,EACN,gBAAgB,EAChB,MAAM,EACN,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,cAAc,EACd,6BAA6B,EAC7B,mBAAmB,CACpB;EACDC,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;EAC1BC,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY;AACtE,CAAC;AAED,OAAO,MAAMC,kBAAkB,GAAG,CAAC,QAAQ,EAAE,iBAAiB,CAAC","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "4.0.1-qa-staging.1",
3
+ "version": "4.0.1-rc.0",
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.0.1-qa-staging.1",
36
+ "@planningcenter/emoji-keyboard": "4.0.0",
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": "a8f74ad625d24f779bab9572927a089dc05b7dd7"
87
+ "gitHead": "f3267650b8c09742984cfcc7869b176db2a51986"
88
88
  }
@@ -1,6 +1,6 @@
1
1
  import { useNavigation } from '@react-navigation/native'
2
2
  import { some } from 'lodash'
3
- import React, { memo, useEffect } from 'react'
3
+ import React, { useEffect } from 'react'
4
4
  import {
5
5
  AccessibilityActionEvent,
6
6
  Pressable,
@@ -44,14 +44,14 @@ import { TheirReplyConnector, MyReplyConnector, AVATAR_CONNECTOR_SPACING } from
44
44
  interface MessageProps extends MessageResource {
45
45
  canDeleteNonAuthoredMessages: boolean
46
46
  conversation_id: number
47
- readByOthers?: boolean
47
+ latestReadMessageSortKey?: string
48
48
  inReplyScreen?: boolean
49
49
  }
50
50
 
51
- export const Message = memo(function MessageRow({
51
+ export function Message({
52
52
  canDeleteNonAuthoredMessages,
53
53
  conversation_id,
54
- readByOthers,
54
+ latestReadMessageSortKey,
55
55
  inReplyScreen,
56
56
  ...message
57
57
  }: MessageProps) {
@@ -73,16 +73,11 @@ export const Message = memo(function MessageRow({
73
73
  const [messageBubbleHeight, setMessageBubbleHeight] = React.useState(0)
74
74
  const { animatedBackgroundColor, handleMessagePressIn, handleMessagePressOut } =
75
75
  useAnimatedMessageBackgroundColor()
76
- const isReplyRootMessage = message.replyRootId === message.id
77
- const isDeletedReplyRootMessage = isReplyRootMessage && !!message.deletedAt
78
- const showReadReceipts = message.mine && !pending && !error
79
- const replyToReplyRootMessage = !isReplyRootMessage && !!message.replyRootId
80
- const { message: fetchedReplyRoot } = useConversationMessage({
76
+ const { message: replyRootMessage } = useConversationMessage({
81
77
  conversation_id,
82
78
  messageId: message.replyRootId || '',
83
- enabled: replyToReplyRootMessage && !message.replyRoot,
79
+ enabled: !!message.replyRootId,
84
80
  })
85
- const replyRoot = message.replyRoot ?? fetchedReplyRoot
86
81
 
87
82
  const metaProps = {
88
83
  authorName: author.name,
@@ -90,11 +85,14 @@ export const Message = memo(function MessageRow({
90
85
  }
91
86
 
92
87
  const renderAuthor = (!message.mine && message.renderAuthor) || false
93
- const showReplyCountButton = !inReplyScreen && isReplyRootMessage
88
+ const showReplyCountButton = !inReplyScreen && message.replyRootId === message.id
89
+ const isReplyRootMessage = message.replyRootId === message.id
90
+ const isDeletedReplyRootMessage = isReplyRootMessage && !!message.deletedAt
91
+ const replyToReplyRootMessage = !isReplyRootMessage && !!message.replyRootId
94
92
 
95
93
  const replyCountText = pluralize(message.replyCount, 'reply')
96
94
  const messagePendingLabel = isPersisted ? 'Saving' : 'Sending'
97
- const replyRootAuthorName = replyToReplyRootMessage ? replyRoot?.author.name : author.name
95
+ const replyRootAuthorName = message.replyRootId ? replyRootMessage?.author.name : author.name
98
96
  const messageText = isDeletedReplyRootMessage ? 'Message deleted' : text
99
97
 
100
98
  const messageBottomMargin =
@@ -286,7 +284,12 @@ export const Message = memo(function MessageRow({
286
284
  )}
287
285
  {showMessageMeta && !isDeletedReplyRootMessage && (
288
286
  <View style={styles.messageMeta}>
289
- {showReadReceipts && <MessageReadReceipts read={readByOthers} />}
287
+ {message.mine && !pending && !error && (
288
+ <MessageReadReceipts
289
+ message={message}
290
+ latestReadMessageSortKey={latestReadMessageSortKey}
291
+ />
292
+ )}
290
293
  {error ? (
291
294
  <View style={styles.errorContainer}>
292
295
  {retryFailedSaveMutation.isPending ? (
@@ -335,7 +338,7 @@ export const Message = memo(function MessageRow({
335
338
  </Animated.View>
336
339
  </Pressable>
337
340
  )
338
- })
341
+ }
339
342
 
340
343
  const useMessageStyles = (mine: boolean, isDeleting: boolean) => {
341
344
  const { colors } = useTheme()
@@ -1,15 +1,17 @@
1
1
  import React from 'react'
2
2
  import { StyleSheet, View } from 'react-native'
3
3
  import { useTheme } from '../../hooks'
4
+ import { MessageResource } from '../../types'
4
5
  import { Icon, Text } from '../display'
5
6
 
6
7
  interface Props {
7
- read?: boolean
8
+ message: MessageResource
9
+ latestReadMessageSortKey?: string
8
10
  }
9
11
 
10
- export function MessageReadReceipts({ read }: Props) {
12
+ export function MessageReadReceipts({ message, latestReadMessageSortKey }: Props) {
11
13
  const styles = useStyles()
12
- if (!read) {
14
+ if (!latestReadMessageSortKey || message.id > latestReadMessageSortKey) {
13
15
  return (
14
16
  <View style={styles.badgeContainer}>
15
17
  <Icon name="general.check" style={styles.icon} />