@planningcenter/chat-react-native 3.0.0 → 3.1.0-rc.1

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 (82) hide show
  1. package/build/components/display/badge.js +3 -0
  2. package/build/components/display/badge.js.map +1 -1
  3. package/build/components/display/index.d.ts +5 -4
  4. package/build/components/display/index.d.ts.map +1 -1
  5. package/build/components/display/index.js +5 -4
  6. package/build/components/display/index.js.map +1 -1
  7. package/build/components/display/person.d.ts +10 -0
  8. package/build/components/display/person.d.ts.map +1 -0
  9. package/build/components/display/person.js +67 -0
  10. package/build/components/display/person.js.map +1 -0
  11. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  12. package/build/hooks/use_conversation_messages.js +5 -0
  13. package/build/hooks/use_conversation_messages.js.map +1 -1
  14. package/build/hooks/use_conversation_messages_jolt_events.d.ts +7 -0
  15. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -0
  16. package/build/hooks/use_conversation_messages_jolt_events.js +36 -0
  17. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -0
  18. package/build/hooks/use_current_person.d.ts +2 -2
  19. package/build/hooks/use_current_person.d.ts.map +1 -1
  20. package/build/hooks/use_current_person.js.map +1 -1
  21. package/build/screens/conversation_details_screen.js +2 -16
  22. package/build/screens/conversation_details_screen.js.map +1 -1
  23. package/build/screens/design_system_screen.d.ts.map +1 -1
  24. package/build/screens/design_system_screen.js +29 -2
  25. package/build/screens/design_system_screen.js.map +1 -1
  26. package/build/types/jolt_events/conversation_events.d.ts +38 -0
  27. package/build/types/jolt_events/conversation_events.d.ts.map +1 -0
  28. package/build/types/jolt_events/conversation_events.js +2 -0
  29. package/build/types/jolt_events/conversation_events.js.map +1 -0
  30. package/build/types/jolt_events/index.d.ts +10 -0
  31. package/build/types/jolt_events/index.d.ts.map +1 -0
  32. package/build/types/jolt_events/index.js +2 -0
  33. package/build/types/jolt_events/index.js.map +1 -0
  34. package/build/types/jolt_events/message_events.d.ts +32 -0
  35. package/build/types/jolt_events/message_events.d.ts.map +1 -0
  36. package/build/types/jolt_events/message_events.js +2 -0
  37. package/build/types/jolt_events/message_events.js.map +1 -0
  38. package/build/types/jolt_events/reaction_events.d.ts +25 -0
  39. package/build/types/jolt_events/reaction_events.d.ts.map +1 -0
  40. package/build/types/jolt_events/reaction_events.js +2 -0
  41. package/build/types/jolt_events/reaction_events.js.map +1 -0
  42. package/build/types/jolt_events/typing_events.d.ts +15 -0
  43. package/build/types/jolt_events/typing_events.d.ts.map +1 -0
  44. package/build/types/jolt_events/typing_events.js +2 -0
  45. package/build/types/jolt_events/typing_events.js.map +1 -0
  46. package/build/types/resources/denormalized_attachment_resource.d.ts +88 -0
  47. package/build/types/resources/denormalized_attachment_resource.d.ts.map +1 -0
  48. package/build/types/resources/denormalized_attachment_resource.js +6 -0
  49. package/build/types/resources/denormalized_attachment_resource.js.map +1 -0
  50. package/build/types/resources/message.d.ts +4 -1
  51. package/build/types/resources/message.d.ts.map +1 -1
  52. package/build/types/resources/message.js.map +1 -1
  53. package/build/types/resources/person.d.ts +2 -0
  54. package/build/types/resources/person.d.ts.map +1 -1
  55. package/build/types/resources/person.js.map +1 -1
  56. package/build/utils/deepCamelCaseKeys.d.ts +4 -0
  57. package/build/utils/deepCamelCaseKeys.d.ts.map +1 -0
  58. package/build/utils/deepCamelCaseKeys.js +11 -0
  59. package/build/utils/deepCamelCaseKeys.js.map +1 -0
  60. package/build/utils/jolt/transform_message_event_data_to_message_resource.d.ts +7 -0
  61. package/build/utils/jolt/transform_message_event_data_to_message_resource.d.ts.map +1 -0
  62. package/build/utils/jolt/transform_message_event_data_to_message_resource.js +22 -0
  63. package/build/utils/jolt/transform_message_event_data_to_message_resource.js.map +1 -0
  64. package/package.json +2 -2
  65. package/src/components/display/badge.tsx +3 -0
  66. package/src/components/display/index.ts +5 -4
  67. package/src/components/display/person.tsx +90 -0
  68. package/src/hooks/use_conversation_messages.ts +6 -0
  69. package/src/hooks/use_conversation_messages_jolt_events.ts +51 -0
  70. package/src/hooks/use_current_person.ts +2 -2
  71. package/src/screens/conversation_details_screen.tsx +3 -30
  72. package/src/screens/design_system_screen.tsx +37 -1
  73. package/src/types/jolt_events/conversation_events.ts +41 -0
  74. package/src/types/jolt_events/index.ts +28 -0
  75. package/src/types/jolt_events/message_events.ts +34 -0
  76. package/src/types/jolt_events/reaction_events.ts +26 -0
  77. package/src/types/jolt_events/typing_events.ts +16 -0
  78. package/src/types/resources/denormalized_attachment_resource.ts +101 -0
  79. package/src/types/resources/message.ts +4 -1
  80. package/src/types/resources/person.ts +3 -0
  81. package/src/utils/deepCamelCaseKeys.ts +15 -0
  82. package/src/utils/jolt/transform_message_event_data_to_message_resource.ts +31 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * This is the type of message attachment that is denormalized onto the message resource.
3
+ * It is what we receive from `MessageVertex#attachments`.
4
+ */
5
+ export type DenormalizedAttachmentResource = DenormalizedMessageAttachmentResource | DenormalizedGiphyAttachmentResource | DenormalizedExpandedLinkAttachmentResource;
6
+ export type DenormalizedAttachmentResourceForCreate = DenormalizedMessageAttachmentResourceForCreate | DenormalizedGiphyAttachmentResourceForCreate | DenormalizedExpandedLinkAttachmentResource;
7
+ interface GenericAttachmentResource {
8
+ type: string;
9
+ id?: string;
10
+ [key: string]: unknown;
11
+ }
12
+ export interface DenormalizedMessageAttachmentResource extends GenericAttachmentResource {
13
+ type: 'MessageAttachment';
14
+ id: string;
15
+ attributes: {
16
+ filename: string;
17
+ key: string;
18
+ contentType: string;
19
+ byteSize: number;
20
+ checksum: string;
21
+ metadata?: {
22
+ width?: number;
23
+ height?: number;
24
+ analyzed?: boolean;
25
+ identified?: boolean;
26
+ };
27
+ url: string;
28
+ urlMedium?: string;
29
+ };
30
+ }
31
+ export interface DenormalizedMessageAttachmentResourceForCreate extends GenericAttachmentResource {
32
+ type: 'MessageAttachment';
33
+ id: string;
34
+ }
35
+ export interface DenormalizedGiphyAttachmentResource extends GenericAttachmentResource {
36
+ type: 'giphy';
37
+ id: string;
38
+ title: string;
39
+ originalGiphyTitle?: string;
40
+ titleLink: string;
41
+ thumbUrl: string;
42
+ giphy: {
43
+ original: GiphyVariant;
44
+ fixedHeight: GiphyVariant;
45
+ fixedHeightStill: GiphyVariant;
46
+ fixedHeightDownsampled: GiphyVariant;
47
+ fixedWidth: GiphyVariant;
48
+ fixedWidthStill: GiphyVariant;
49
+ fixedWidthDownsampled: GiphyVariant;
50
+ };
51
+ }
52
+ export interface DenormalizedGiphyAttachmentResourceForCreate extends GenericAttachmentResource {
53
+ type: 'giphy';
54
+ id: string;
55
+ title: string;
56
+ original_giphy_title: string;
57
+ title_link: string;
58
+ thumb_url: string;
59
+ giphy: {
60
+ original: GiphyVariant;
61
+ fixed_height: GiphyVariant;
62
+ fixed_height_still: GiphyVariant;
63
+ fixed_height_downsampled: GiphyVariant;
64
+ fixed_width: GiphyVariant;
65
+ fixed_width_still: GiphyVariant;
66
+ fixed_width_downsampled: GiphyVariant;
67
+ };
68
+ }
69
+ interface GiphyVariant {
70
+ url: string;
71
+ width: number;
72
+ height: number;
73
+ size: string;
74
+ frames: string;
75
+ }
76
+ export interface DenormalizedExpandedLinkAttachmentResource extends GenericAttachmentResource {
77
+ type: 'ExpandedLink';
78
+ attributes: {
79
+ url: string;
80
+ title?: string;
81
+ description?: string;
82
+ imageUrl?: string;
83
+ imageHeight?: number;
84
+ imageWidth?: number;
85
+ };
86
+ }
87
+ export {};
88
+ //# sourceMappingURL=denormalized_attachment_resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"denormalized_attachment_resource.d.ts","sourceRoot":"","sources":["../../../src/types/resources/denormalized_attachment_resource.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * This is the type of message attachment that is denormalized onto the message resource.
3
+ * It is what we receive from `MessageVertex#attachments`.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=denormalized_attachment_resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"denormalized_attachment_resource.js","sourceRoot":"","sources":["../../../src/types/resources/denormalized_attachment_resource.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This is the type of message attachment that is denormalized onto the message resource.\n * It is what we receive from `MessageVertex#attachments`.\n */\n\nexport type DenormalizedAttachmentResource =\n | DenormalizedMessageAttachmentResource\n | DenormalizedGiphyAttachmentResource\n | DenormalizedExpandedLinkAttachmentResource\n\nexport type DenormalizedAttachmentResourceForCreate =\n | DenormalizedMessageAttachmentResourceForCreate\n | DenormalizedGiphyAttachmentResourceForCreate\n | DenormalizedExpandedLinkAttachmentResource\n\ninterface GenericAttachmentResource {\n type: string\n id?: string\n [key: string]: unknown\n}\n\nexport interface DenormalizedMessageAttachmentResource extends GenericAttachmentResource {\n type: 'MessageAttachment'\n id: string\n attributes: {\n filename: string\n key: string\n contentType: string\n byteSize: number\n checksum: string\n metadata?: {\n width?: number\n height?: number\n analyzed?: boolean\n identified?: boolean\n }\n url: string\n urlMedium?: string\n }\n}\n\nexport interface DenormalizedMessageAttachmentResourceForCreate extends GenericAttachmentResource {\n type: 'MessageAttachment'\n id: string\n}\n\nexport interface DenormalizedGiphyAttachmentResource extends GenericAttachmentResource {\n type: 'giphy'\n id: string\n title: string\n originalGiphyTitle?: string\n titleLink: string\n thumbUrl: string\n giphy: {\n original: GiphyVariant\n fixedHeight: GiphyVariant\n fixedHeightStill: GiphyVariant\n fixedHeightDownsampled: GiphyVariant\n fixedWidth: GiphyVariant\n fixedWidthStill: GiphyVariant\n fixedWidthDownsampled: GiphyVariant\n }\n}\n\nexport interface DenormalizedGiphyAttachmentResourceForCreate extends GenericAttachmentResource {\n type: 'giphy'\n id: string\n title: string\n original_giphy_title: string\n title_link: string\n thumb_url: string\n giphy: {\n original: GiphyVariant\n fixed_height: GiphyVariant\n fixed_height_still: GiphyVariant\n fixed_height_downsampled: GiphyVariant\n fixed_width: GiphyVariant\n fixed_width_still: GiphyVariant\n fixed_width_downsampled: GiphyVariant\n }\n}\n\ninterface GiphyVariant {\n url: string\n width: number\n height: number\n size: string\n frames: string\n}\n\nexport interface DenormalizedExpandedLinkAttachmentResource extends GenericAttachmentResource {\n type: 'ExpandedLink'\n attributes: {\n url: string\n title?: string\n description?: string\n imageUrl?: string\n imageHeight?: number\n imageWidth?: number\n }\n}\n"]}
@@ -1,13 +1,16 @@
1
+ import { DenormalizedAttachmentResource } from './denormalized_attachment_resource';
1
2
  import type { PersonResource } from './person';
2
3
  import type { ReactionCountResource } from './reaction';
3
4
  export interface MessageResource {
4
5
  type: 'Message';
5
6
  id: string;
6
7
  text: string;
8
+ html: string;
7
9
  createdAt: string;
10
+ deletedAt: string | null;
8
11
  textEditedAt: string | null;
9
12
  mine: boolean;
10
- attachments: unknown[];
13
+ attachments: DenormalizedAttachmentResource[];
11
14
  author: PersonResource;
12
15
  reactionCounts: ReactionCountResource[];
13
16
  renderAuthor?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/types/resources/message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE,OAAO,EAAE,CAAA;IACtB,MAAM,EAAE,cAAc,CAAA;IACtB,cAAc,EAAE,qBAAqB,EAAE,CAAA;IAGvC,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB"}
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/types/resources/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,oCAAoC,CAAA;AACnF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE,8BAA8B,EAAE,CAAA;IAC7C,MAAM,EAAE,cAAc,CAAA;IACtB,cAAc,EAAE,qBAAqB,EAAE,CAAA;IAGvC,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/types/resources/message.ts"],"names":[],"mappings":"","sourcesContent":["import type { PersonResource } from './person'\nimport type { ReactionCountResource } from './reaction'\n\nexport interface MessageResource {\n type: 'Message'\n id: string\n text: string\n createdAt: string\n textEditedAt: string | null\n mine: boolean\n attachments: unknown[]\n author: PersonResource\n reactionCounts: ReactionCountResource[]\n\n // Custom Local Properties we set for rendering\n renderAuthor?: boolean\n renderTime?: boolean\n}\n"]}
1
+ {"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/types/resources/message.ts"],"names":[],"mappings":"","sourcesContent":["import { DenormalizedAttachmentResource } from './denormalized_attachment_resource'\nimport type { PersonResource } from './person'\nimport type { ReactionCountResource } from './reaction'\n\nexport interface MessageResource {\n type: 'Message'\n id: string\n text: string\n html: string\n createdAt: string\n deletedAt: string | null\n textEditedAt: string | null\n mine: boolean\n attachments: DenormalizedAttachmentResource[]\n author: PersonResource\n reactionCounts: ReactionCountResource[]\n\n // Custom Local Properties we set for rendering\n renderAuthor?: boolean\n renderTime?: boolean\n}\n"]}
@@ -2,6 +2,8 @@ import { ResourceObject } from '../api_primitives';
2
2
  export interface PersonResource extends ResourceObject {
3
3
  name: string;
4
4
  avatar: string;
5
+ }
6
+ export interface CurrentPersonResource extends PersonResource {
5
7
  canChat: boolean;
6
8
  unreadCount: number;
7
9
  pcoChatEnabled: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"person.d.ts","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,OAAO,CAAA;CACxB"}
1
+ {"version":3,"file":"person.d.ts","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,qBAAsB,SAAQ,cAAc;IAC3D,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,OAAO,CAAA;CACxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"person.js","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"","sourcesContent":["import { ResourceObject } from '../api_primitives'\n\nexport interface PersonResource extends ResourceObject {\n name: string\n avatar: string\n canChat: boolean\n unreadCount: number\n pcoChatEnabled: boolean\n}\n"]}
1
+ {"version":3,"file":"person.js","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"","sourcesContent":["import { ResourceObject } from '../api_primitives'\n\nexport interface PersonResource extends ResourceObject {\n name: string\n avatar: string\n}\n\nexport interface CurrentPersonResource extends PersonResource {\n canChat: boolean\n unreadCount: number\n pcoChatEnabled: boolean\n}\n"]}
@@ -0,0 +1,4 @@
1
+ type ObjType = Record<string, unknown> | unknown[] | unknown;
2
+ export declare function deepCamelCaseKeys<T extends ObjType>(obj: T): T;
3
+ export {};
4
+ //# sourceMappingURL=deepCamelCaseKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deepCamelCaseKeys.d.ts","sourceRoot":"","sources":["../../src/utils/deepCamelCaseKeys.ts"],"names":[],"mappings":"AAEA,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,OAAO,CAAA;AAE5D,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAU9D"}
@@ -0,0 +1,11 @@
1
+ import { camelCase, isArray, isObject, mapKeys, mapValues } from 'lodash';
2
+ export function deepCamelCaseKeys(obj) {
3
+ if (isArray(obj)) {
4
+ return obj.map(deepCamelCaseKeys);
5
+ }
6
+ else if (isObject(obj)) {
7
+ return mapValues(mapKeys(obj, (_value, key) => camelCase(key)), deepCamelCaseKeys);
8
+ }
9
+ return obj;
10
+ }
11
+ //# sourceMappingURL=deepCamelCaseKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deepCamelCaseKeys.js","sourceRoot":"","sources":["../../src/utils/deepCamelCaseKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAIzE,MAAM,UAAU,iBAAiB,CAAoB,GAAM;IACzD,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACjB,OAAQ,GAAiB,CAAC,GAAG,CAAC,iBAAiB,CAAM,CAAA;IACvD,CAAC;SAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,SAAS,CACd,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAC7C,iBAAiB,CACb,CAAA;IACR,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["import { camelCase, isArray, isObject, mapKeys, mapValues } from 'lodash'\n\ntype ObjType = Record<string, unknown> | unknown[] | unknown\n\nexport function deepCamelCaseKeys<T extends ObjType>(obj: T): T {\n if (isArray(obj)) {\n return (obj as T & any[]).map(deepCamelCaseKeys) as T\n } else if (isObject(obj)) {\n return mapValues(\n mapKeys(obj, (_value, key) => camelCase(key)),\n deepCamelCaseKeys\n ) as T\n }\n return obj\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { MessageResource } from '../../types';
2
+ import { MessageCreatedEvent } from '../../types/jolt_events/message_events';
3
+ export declare function transformMessageEventDataToMessageResource({ data, currentPersonId, }: {
4
+ data: MessageCreatedEvent['data']['data'];
5
+ currentPersonId: string;
6
+ }): MessageResource;
7
+ //# sourceMappingURL=transform_message_event_data_to_message_resource.d.ts.map
@@ -0,0 +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,CAmBlB"}
@@ -0,0 +1,22 @@
1
+ import { deepCamelCaseKeys } from '../deepCamelCaseKeys';
2
+ export function transformMessageEventDataToMessageResource({ data, currentPersonId, }) {
3
+ return {
4
+ type: 'Message',
5
+ id: data.sort_key,
6
+ text: data.text,
7
+ html: data.html,
8
+ createdAt: data.created_at,
9
+ deletedAt: data.deleted_at,
10
+ textEditedAt: data.text_edited_at,
11
+ mine: data.author_id.toString() === currentPersonId.toString(),
12
+ attachments: deepCamelCaseKeys(data.attachments) || [],
13
+ author: {
14
+ type: 'Person',
15
+ id: data.author_id.toString(),
16
+ name: data.author_name,
17
+ avatar: data.author_avatar,
18
+ },
19
+ reactionCounts: [],
20
+ };
21
+ }
22
+ //# sourceMappingURL=transform_message_event_data_to_message_resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform_message_event_data_to_message_resource.js","sourceRoot":"","sources":["../../../src/utils/jolt/transform_message_event_data_to_message_resource.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAExD,MAAM,UAAU,0CAA0C,CAAC,EACzD,IAAI,EACJ,eAAe,GAIhB;IACC,OAAO;QACL,IAAI,EAAE,SAAS;QACf,EAAE,EAAE,IAAI,CAAC,QAAQ;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,SAAS,EAAE,IAAI,CAAC,UAAU;QAC1B,SAAS,EAAE,IAAI,CAAC,UAAU;QAC1B,YAAY,EAAE,IAAI,CAAC,cAAc;QACjC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,eAAe,CAAC,QAAQ,EAAE;QAC9D,WAAW,EAAE,iBAAiB,CAAmC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;QACxF,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE;YAC7B,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,MAAM,EAAE,IAAI,CAAC,aAAa;SAC3B;QACD,cAAc,EAAE,EAAE;KACnB,CAAA;AACH,CAAC","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: string\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.toString() === currentPersonId.toString(),\n attachments: deepCamelCaseKeys<DenormalizedAttachmentResource[]>(data.attachments) || [],\n author: {\n type: 'Person',\n id: data.author_id.toString(),\n name: data.author_name,\n avatar: data.author_avatar,\n },\n reactionCounts: [],\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.0.0",
3
+ "version": "3.1.0-rc.1",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -52,5 +52,5 @@
52
52
  "prettier": "^3.4.2",
53
53
  "typescript": "<5.6.0"
54
54
  },
55
- "gitHead": "9ba41b63c9b41a8a118a36b4d14019fe90fe3368"
55
+ "gitHead": "a653776f157e5b79468f1221233ea8a082dc009e"
56
56
  }
@@ -181,6 +181,7 @@ const useStyles = ({
181
181
  flexDirection: 'row',
182
182
  alignItems: 'center',
183
183
  justifyContent: 'center',
184
+ alignSelf: 'flex-start',
184
185
  borderRadius: variantStylesMap[variant].borderRadius,
185
186
  borderWidth: variantStylesMap[variant].borderWidth,
186
187
  borderColor: statusColorMap[appearance].background,
@@ -205,12 +206,14 @@ const useStyles = ({
205
206
  color: variantStylesMap[variant].textColor,
206
207
  fontWeight: variantStylesMap[variant].fontWeight,
207
208
  fontSize: badgeFontSize,
209
+ lineHeight: 15 * fontScale,
208
210
  },
209
211
  metaLabel: {
210
212
  paddingHorizontal: variantStylesMap[variant].paddingHorizontal,
211
213
  fontSize: badgeFontSize,
212
214
  flexShrink: 1,
213
215
  paddingLeft: variantStylesMap[variant].metaLabelPaddingLeft,
216
+ lineHeight: 15 * fontScale,
214
217
  },
215
218
  })
216
219
  }
@@ -1,15 +1,16 @@
1
- export * from './avatar'
2
1
  export * from './avatar_group'
2
+ export * from './avatar'
3
3
  export * from './badge'
4
- export * from './banner'
5
4
  export * from './banner_collapsible'
5
+ export * from './banner'
6
6
  export * from './button'
7
7
  export * from './heading'
8
- export * from './icon'
9
8
  export * from './icon_button'
9
+ export * from './icon'
10
10
  export * from './image'
11
+ export * from './person'
11
12
  export * from './spinner'
12
13
  export * from './switch'
13
- export * from './text'
14
14
  export * from './text_button'
15
15
  export * from './text_inline_button'
16
+ export * from './text'
@@ -0,0 +1,90 @@
1
+ import React from 'react'
2
+ import { StyleSheet, View } from 'react-native'
3
+ import { useTheme } from '../../hooks'
4
+ import { platformFontWeightMedium } from '../../utils/styles'
5
+ import { MemberResource } from '../../types'
6
+ import { Avatar } from './avatar'
7
+ import { Text } from './text'
8
+ import { Badge } from './badge'
9
+ import { space } from '../../utils'
10
+
11
+ // =================================
12
+ // ====== Components ===============
13
+ // =================================
14
+
15
+ interface PersonProps {
16
+ person: MemberResource
17
+ }
18
+
19
+ export function Person({ person }: PersonProps) {
20
+ return person.child ? <Child person={person} /> : <Adult person={person} />
21
+ }
22
+
23
+ export function Adult({ person }: PersonProps) {
24
+ const styles = useStyles()
25
+
26
+ return (
27
+ <View style={styles.wrapper}>
28
+ <Avatar sourceUri={person.avatar} />
29
+ <View style={styles.content}>
30
+ <Text style={styles.name}>{person.name}</Text>
31
+ <View style={styles.badges}>
32
+ {person.badges?.map((badge, index) => <Badge key={index} label={badge.title} />)}
33
+ </View>
34
+ </View>
35
+ </View>
36
+ )
37
+ }
38
+ export function Child({ person }: PersonProps) {
39
+ const styles = useStyles()
40
+
41
+ return (
42
+ <View style={styles.wrapper}>
43
+ <View style={styles.childAvatar}>
44
+ <Avatar sourceUri={person.avatar} />
45
+ </View>
46
+ <View style={styles.content}>
47
+ <Text style={[styles.name, styles.childName]}>{person.name}</Text>
48
+ <View style={styles.badges}>
49
+ <Badge
50
+ label="Not eligible to chat"
51
+ appearance="warning"
52
+ iconName="general.shieldExclamation"
53
+ />
54
+ </View>
55
+ </View>
56
+ </View>
57
+ )
58
+ }
59
+
60
+ // =================================
61
+ // ====== Styles ===================
62
+ // =================================
63
+
64
+ const useStyles = () => {
65
+ const { colors } = useTheme()
66
+
67
+ return StyleSheet.create({
68
+ wrapper: {
69
+ flexDirection: 'row',
70
+ alignItems: 'center',
71
+ gap: space(1),
72
+ },
73
+ content: {
74
+ gap: space(0.25),
75
+ },
76
+ name: {
77
+ fontWeight: platformFontWeightMedium,
78
+ },
79
+ childName: {
80
+ color: colors.textColorDefaultSecondary,
81
+ },
82
+ childAvatar: {
83
+ opacity: 0.5,
84
+ },
85
+ badges: {
86
+ flexDirection: 'row',
87
+ gap: space(0.5),
88
+ },
89
+ })
90
+ }
@@ -1,4 +1,5 @@
1
1
  import { MessageResource } from '../types'
2
+ import { useConversationMessagesJoltEvents } from './use_conversation_messages_jolt_events'
2
3
  import {
3
4
  getRequestQueryKey,
4
5
  SuspensePaginatorOptions,
@@ -16,6 +17,11 @@ export const useConversationMessages = (
16
17
  const queryKey = getMessagesQueryKey({ conversation_id })
17
18
  const messages = data.sort((a, b) => -a.id.localeCompare(b.id))
18
19
 
20
+ useConversationMessagesJoltEvents({
21
+ conversationId: conversation_id,
22
+ refetchMessages: refetch,
23
+ })
24
+
19
25
  return { messages, refetch, isRefetching, fetchNextPage, queryKey }
20
26
  }
21
27
 
@@ -0,0 +1,51 @@
1
+ import { ApiCollection, MessageResource } from '../types'
2
+ import { useJoltChannel, useJoltEvent } from './use_jolt'
3
+ import { updateRecordInPagesData } from '../utils'
4
+ import { MessageCreatedEvent } from '../types/jolt_events/message_events'
5
+ import { InfiniteData, useQueryClient } from '@tanstack/react-query'
6
+ import { useCurrentPerson } from './use_current_person'
7
+ import { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'
8
+ import { getMessagesRequestArgs } from './use_conversation_messages'
9
+ import { getRequestQueryKey } from './use_suspense_api'
10
+
11
+ interface Props {
12
+ conversationId: string
13
+ refetchMessages?: () => void
14
+ }
15
+
16
+ export function useConversationMessagesJoltEvents({ conversationId, refetchMessages }: Props) {
17
+ const queryClient = useQueryClient()
18
+ const currentPerson = useCurrentPerson()
19
+ const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)
20
+ const messagesRequestArgs = getMessagesRequestArgs({ conversation_id: conversationId })
21
+ const messagesQueryKey = getRequestQueryKey(messagesRequestArgs)
22
+
23
+ const handleMessageJoltEvent = async () => {
24
+ refetchMessages?.()
25
+ }
26
+
27
+ const handleMessageUpdateOrCreate = async (e: MessageCreatedEvent) => {
28
+ const { data } = e.data
29
+ const message = transformMessageEventDataToMessageResource({
30
+ data,
31
+ currentPersonId: currentPerson.id,
32
+ })
33
+
34
+ queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>
35
+ updateRecordInPagesData({
36
+ data: prev,
37
+ record: message,
38
+ processRecord: (record, current) => {
39
+ return { ...current, ...record }
40
+ },
41
+ })
42
+ )
43
+ }
44
+
45
+ useJoltEvent(joltChannel, 'message.created', handleMessageUpdateOrCreate)
46
+ useJoltEvent(joltChannel, 'message.updated', handleMessageUpdateOrCreate)
47
+ useJoltEvent(joltChannel, 'message.deleted', handleMessageJoltEvent)
48
+ useJoltEvent(joltChannel, 'reaction.*', handleMessageJoltEvent)
49
+ }
50
+
51
+ type QueryData = InfiniteData<ApiCollection<MessageResource>>
@@ -1,8 +1,8 @@
1
- import { PersonResource } from '../types'
1
+ import { CurrentPersonResource } from '../types'
2
2
  import { useSuspenseGet } from './use_suspense_api'
3
3
 
4
4
  export const useCurrentPerson = () => {
5
- const { data: person } = useSuspenseGet<PersonResource>({
5
+ const { data: person } = useSuspenseGet<CurrentPersonResource>({
6
6
  url: '/me',
7
7
  data: {
8
8
  fields: {
@@ -15,14 +15,14 @@ import {
15
15
  type ViewStyle,
16
16
  type ViewProps,
17
17
  } from 'react-native'
18
- import { Avatar, Badge, Heading, Icon, Switch, Text } from '../components'
18
+ import { Heading, Icon, Person, Switch, Text } from '../components'
19
19
  import { useSuspenseGet, useTheme } from '../hooks'
20
20
  import {
21
21
  useConversation,
22
22
  useConversationMute,
23
23
  useConversationUpdate,
24
24
  } from '../hooks/use_conversation'
25
- import { MemberBadge, MemberResource, isDefined } from '../types'
25
+ import { MemberResource, isDefined } from '../types'
26
26
  import { HeaderRightButton } from '../navigation/header'
27
27
  import { FlashList } from '@shopify/flash-list'
28
28
  import { space } from '../utils'
@@ -157,7 +157,7 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
157
157
  case SectionTypes.members:
158
158
  return (
159
159
  <ListSection isStart={isStart} isEnd={isEnd} style={item?.sectionStyle}>
160
- <MemberRow {...item.data} />
160
+ <Person person={{ ...item.data }} />
161
161
  </ListSection>
162
162
  )
163
163
  case SectionTypes.setting:
@@ -267,33 +267,6 @@ function SettingRow({
267
267
  )
268
268
  }
269
269
 
270
- interface MemberRowProps {
271
- avatar: string
272
- name: string
273
- style?: ViewStyle
274
- badges?: MemberBadge[]
275
- }
276
-
277
- function MemberRow({ avatar, name, style, badges }: MemberRowProps) {
278
- const styles = useStyles()
279
-
280
- return (
281
- <View style={[styles.member, style]}>
282
- <Avatar sourceUri={avatar} />
283
- <View style={styles.memberBody}>
284
- <Text style={styles.memberName}>{name}</Text>
285
- <View style={styles.memberBadges}>
286
- {badges?.map((badge, index) => (
287
- <View key={index} style={styles.memberBadge}>
288
- <Badge label={badge.title} />
289
- </View>
290
- ))}
291
- </View>
292
- </View>
293
- </View>
294
- )
295
- }
296
-
297
270
  // =================================
298
271
  // ====== Styles ===================
299
272
  // =================================
@@ -13,6 +13,7 @@ import {
13
13
  Icon,
14
14
  IconButton,
15
15
  Image,
16
+ Person,
16
17
  Spinner,
17
18
  Switch,
18
19
  Text,
@@ -50,6 +51,24 @@ const URL = {
50
51
  ],
51
52
  }
52
53
 
54
+ const personAdult = {
55
+ id: '1',
56
+ type: 'Member' as const,
57
+ name: 'John Doe',
58
+ avatar: URL.avatar,
59
+ badges: [{ title: 'Conversation owner' }, { title: 'Leader' }],
60
+ child: false,
61
+ }
62
+
63
+ const personChild = {
64
+ id: '2',
65
+ type: 'Member' as const,
66
+ name: 'Kid McChild',
67
+ avatar: URL.two_avatars[1],
68
+ badges: [],
69
+ child: true,
70
+ }
71
+
53
72
  const buttonPress = () => Alert.alert('Button clicked')
54
73
 
55
74
  // =================================
@@ -69,7 +88,8 @@ export function DesignSystemScreen() {
69
88
  <PressablesSection />
70
89
  <ImageIconsSection />
71
90
  <FormControlsSection />
72
- <StatusComponentsSection isLast />
91
+ <StatusComponentsSection />
92
+ <MiscComponentsSection isLast />
73
93
  </ScrollView>
74
94
  )
75
95
  }
@@ -852,6 +872,22 @@ function StatusComponentsSection({ isLast }: SectionProps) {
852
872
  )
853
873
  }
854
874
 
875
+ function MiscComponentsSection({ isLast }: SectionProps) {
876
+ return (
877
+ <CollapsableSection title="Misc components" isLast={isLast}>
878
+ <Group
879
+ title="Person"
880
+ description="Takes a person object (`MemberResource` type) and displays an avatar, name, and badges. If person is a child we show a special badge and faded styles. Implomentation is based on a similar Chat Web component."
881
+ >
882
+ <Column>
883
+ <Person person={personAdult} />
884
+ <Person person={personChild} />
885
+ </Column>
886
+ </Group>
887
+ </CollapsableSection>
888
+ )
889
+ }
890
+
855
891
  // =================================
856
892
  // ====== Docs UI ==================
857
893
  // =================================
@@ -0,0 +1,41 @@
1
+ import type { CustomMessage } from '@planningcenter/jolt-client/dist/types/JoltConnection'
2
+
3
+ type DateString = string
4
+ interface BaseConversationEventData extends Record<string, unknown> {
5
+ data: {
6
+ id: number
7
+ archived_at: DateString
8
+ created_at: DateString
9
+ last_message_author_id?: number
10
+ last_message_author_name?: string
11
+ last_message_created_at?: DateString
12
+ last_message_sort_key?: string
13
+ last_message_text_preview?: string
14
+ latest_read_message_sort_key?: string
15
+ organization_id: number
16
+ replies_disabled: boolean
17
+ subtitle?: string
18
+ title: string
19
+ updated_at: DateString
20
+ }
21
+ }
22
+
23
+ export interface ConversationCreatedEvent extends CustomMessage {
24
+ event: 'conversation.created'
25
+ data: BaseConversationEventData
26
+ }
27
+
28
+ export interface ConversationUpdatedEvent extends CustomMessage {
29
+ event: 'conversation.updated'
30
+ data: BaseConversationEventData
31
+ }
32
+
33
+ export interface ConversationDeletedEvent extends CustomMessage {
34
+ event: 'conversation.destroyed'
35
+ data: BaseConversationEventData
36
+ }
37
+
38
+ export interface ConversationReadEvent extends CustomMessage {
39
+ event: 'conversation.read'
40
+ data: BaseConversationEventData
41
+ }