@planningcenter/chat-react-native 3.13.2-rc.2 → 3.14.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/build/index.d.ts +1 -1
  2. package/build/index.d.ts.map +1 -1
  3. package/build/index.js +1 -1
  4. package/build/index.js.map +1 -1
  5. package/build/screens/conversation_new/components/services_form.js +7 -3
  6. package/build/screens/conversation_new/components/services_form.js.map +1 -1
  7. package/build/screens/conversations/components/chat_group_badge.js.map +1 -1
  8. package/build/screens/conversations/components/list_header_component.js.map +1 -1
  9. package/build/screens/conversations/conversations_screen.d.ts +2 -2
  10. package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
  11. package/build/screens/conversations/conversations_screen.js.map +1 -1
  12. package/build/screens/design_system_screen.d.ts.map +1 -1
  13. package/build/screens/design_system_screen.js +54 -2
  14. package/build/screens/design_system_screen.js.map +1 -1
  15. package/build/screens/index.d.ts +18 -0
  16. package/build/screens/index.d.ts.map +1 -1
  17. package/build/screens/index.js +18 -0
  18. package/build/screens/index.js.map +1 -1
  19. package/build/utils/date.js +3 -3
  20. package/build/utils/date.js.map +1 -1
  21. package/build/utils/native_adapters/configuration.d.ts +3 -0
  22. package/build/utils/native_adapters/configuration.d.ts.map +1 -1
  23. package/build/utils/native_adapters/configuration.js +3 -0
  24. package/build/utils/native_adapters/configuration.js.map +1 -1
  25. package/build/utils/native_adapters/haptic.d.ts +23 -0
  26. package/build/utils/native_adapters/haptic.d.ts.map +1 -0
  27. package/build/utils/native_adapters/haptic.js +22 -0
  28. package/build/utils/native_adapters/haptic.js.map +1 -0
  29. package/build/utils/native_adapters/index.d.ts +1 -0
  30. package/build/utils/native_adapters/index.d.ts.map +1 -1
  31. package/build/utils/native_adapters/index.js +1 -0
  32. package/build/utils/native_adapters/index.js.map +1 -1
  33. package/package.json +2 -2
  34. package/src/__tests__/utils/native_adapters/configuration.ts +46 -1
  35. package/src/index.tsx +1 -1
  36. package/src/screens/conversation_new/components/services_form.tsx +14 -9
  37. package/src/screens/conversations/components/chat_group_badge.tsx +2 -2
  38. package/src/screens/conversations/components/list_header_component.tsx +2 -2
  39. package/src/screens/conversations/conversations_screen.tsx +2 -2
  40. package/src/screens/design_system_screen.tsx +66 -1
  41. package/src/screens/index.ts +18 -0
  42. package/src/utils/date.ts +3 -3
  43. package/src/utils/native_adapters/configuration.ts +5 -0
  44. package/src/utils/native_adapters/haptic.ts +34 -0
  45. package/src/utils/native_adapters/index.ts +1 -0
@@ -0,0 +1,23 @@
1
+ interface Haptic {
2
+ impactLight: () => void;
3
+ impactMedium: () => void;
4
+ impactHeavy: () => void;
5
+ rigid: () => void;
6
+ soft: () => void;
7
+ notificationSuccess: () => void;
8
+ notificationWarning: () => void;
9
+ notificationError: () => void;
10
+ }
11
+ export declare class HapticAdapter {
12
+ impactLight: () => void;
13
+ impactMedium: () => void;
14
+ impactHeavy: () => void;
15
+ rigid: () => void;
16
+ soft: () => void;
17
+ notificationSuccess: () => void;
18
+ notificationWarning: () => void;
19
+ notificationError: () => void;
20
+ constructor(methods?: Haptic);
21
+ }
22
+ export {};
23
+ //# sourceMappingURL=haptic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"haptic.d.ts","sourceRoot":"","sources":["../../../src/utils/native_adapters/haptic.ts"],"names":[],"mappings":"AAEA,UAAU,MAAM;IACd,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,YAAY,EAAE,MAAM,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,mBAAmB,EAAE,MAAM,IAAI,CAAA;IAC/B,mBAAmB,EAAE,MAAM,IAAI,CAAA;IAC/B,iBAAiB,EAAE,MAAM,IAAI,CAAA;CAC9B;AAED,qBAAa,aAAa;IACxB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,YAAY,EAAE,MAAM,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,mBAAmB,EAAE,MAAM,IAAI,CAAA;IAC/B,mBAAmB,EAAE,MAAM,IAAI,CAAA;IAC/B,iBAAiB,EAAE,MAAM,IAAI,CAAA;gBAEjB,OAAO,CAAC,EAAE,MAAM;CAU7B"}
@@ -0,0 +1,22 @@
1
+ import { noop } from 'lodash';
2
+ export class HapticAdapter {
3
+ impactLight;
4
+ impactMedium;
5
+ impactHeavy;
6
+ rigid;
7
+ soft;
8
+ notificationSuccess;
9
+ notificationWarning;
10
+ notificationError;
11
+ constructor(methods) {
12
+ this.impactLight = methods?.impactLight ?? noop;
13
+ this.impactMedium = methods?.impactMedium ?? noop;
14
+ this.impactHeavy = methods?.impactHeavy ?? noop;
15
+ this.rigid = methods?.rigid ?? noop;
16
+ this.soft = methods?.soft ?? noop;
17
+ this.notificationSuccess = methods?.notificationSuccess ?? noop;
18
+ this.notificationWarning = methods?.notificationWarning ?? noop;
19
+ this.notificationError = methods?.notificationError ?? noop;
20
+ }
21
+ }
22
+ //# sourceMappingURL=haptic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"haptic.js","sourceRoot":"","sources":["../../../src/utils/native_adapters/haptic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAa7B,MAAM,OAAO,aAAa;IACxB,WAAW,CAAY;IACvB,YAAY,CAAY;IACxB,WAAW,CAAY;IACvB,KAAK,CAAY;IACjB,IAAI,CAAY;IAChB,mBAAmB,CAAY;IAC/B,mBAAmB,CAAY;IAC/B,iBAAiB,CAAY;IAE7B,YAAY,OAAgB;QAC1B,IAAI,CAAC,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,IAAI,CAAA;QAC/C,IAAI,CAAC,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,IAAI,CAAA;QACjD,IAAI,CAAC,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,IAAI,CAAA;QAC/C,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,IAAI,CAAA;QACnC,IAAI,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,IAAI,CAAA;QACjC,IAAI,CAAC,mBAAmB,GAAG,OAAO,EAAE,mBAAmB,IAAI,IAAI,CAAA;QAC/D,IAAI,CAAC,mBAAmB,GAAG,OAAO,EAAE,mBAAmB,IAAI,IAAI,CAAA;QAC/D,IAAI,CAAC,iBAAiB,GAAG,OAAO,EAAE,iBAAiB,IAAI,IAAI,CAAA;IAC7D,CAAC;CACF","sourcesContent":["import { noop } from 'lodash'\n\ninterface Haptic {\n impactLight: () => void\n impactMedium: () => void\n impactHeavy: () => void\n rigid: () => void\n soft: () => void\n notificationSuccess: () => void\n notificationWarning: () => void\n notificationError: () => void\n}\n\nexport class HapticAdapter {\n impactLight: () => void\n impactMedium: () => void\n impactHeavy: () => void\n rigid: () => void\n soft: () => void\n notificationSuccess: () => void\n notificationWarning: () => void\n notificationError: () => void\n\n constructor(methods?: Haptic) {\n this.impactLight = methods?.impactLight ?? noop\n this.impactMedium = methods?.impactMedium ?? noop\n this.impactHeavy = methods?.impactHeavy ?? noop\n this.rigid = methods?.rigid ?? noop\n this.soft = methods?.soft ?? noop\n this.notificationSuccess = methods?.notificationSuccess ?? noop\n this.notificationWarning = methods?.notificationWarning ?? noop\n this.notificationError = methods?.notificationError ?? noop\n }\n}\n"]}
@@ -5,4 +5,5 @@ export * from './image_picker';
5
5
  export * from './linking';
6
6
  export * from './log';
7
7
  export * from './video';
8
+ export * from './haptic';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/native_adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/native_adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA"}
@@ -5,4 +5,5 @@ export * from './image_picker';
5
5
  export * from './linking';
6
6
  export * from './log';
7
7
  export * from './video';
8
+ export * from './haptic';
8
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/native_adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA","sourcesContent":["export * from './audio'\nexport * from './clipboard'\nexport * from './configuration'\nexport * from './image_picker'\nexport * from './linking'\nexport * from './log'\nexport * from './video'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/native_adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA","sourcesContent":["export * from './audio'\nexport * from './clipboard'\nexport * from './configuration'\nexport * from './image_picker'\nexport * from './linking'\nexport * from './log'\nexport * from './video'\nexport * from './haptic'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.13.2-rc.2",
3
+ "version": "3.14.0-rc.0",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -55,5 +55,5 @@
55
55
  "react-native-url-polyfill": "^2.0.0",
56
56
  "typescript": "<5.6.0"
57
57
  },
58
- "gitHead": "040731f1e9421a7452a06a499dabb68af8e73f7b"
58
+ "gitHead": "7581413aff42fdbe77cb4c646ab7bc38fafbb4fe"
59
59
  }
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react'
2
2
  import { Linking as RNLinking } from 'react-native'
3
- import { ChatAdapters, Linking } from '../../../utils/native_adapters/configuration'
3
+ import { ChatAdapters, Linking, Haptic } from '../../../utils/native_adapters/configuration'
4
4
  import {
5
5
  AudioAdapter,
6
6
  Clipboard,
@@ -10,6 +10,7 @@ import {
10
10
  VideoAdapter,
11
11
  } from '../../../utils/native_adapters'
12
12
  import { VideoPlayerHandle, VideoPlayerProps } from '../../../utils/native_adapters/video'
13
+ import { HapticAdapter } from '../../../utils/native_adapters/haptic'
13
14
 
14
15
  describe('ChatAdapters', () => {
15
16
  const getStringAsync = jest.fn(async () => '')
@@ -36,6 +37,16 @@ describe('ChatAdapters', () => {
36
37
  openCameraAsync: async () => ({ canceled: true, assets: null }),
37
38
  openImageLibraryAsync: async () => ({ canceled: true, assets: null }),
38
39
  })
40
+ const haptic = new HapticAdapter({
41
+ impactLight: jest.fn(),
42
+ impactMedium: jest.fn(),
43
+ impactHeavy: jest.fn(),
44
+ rigid: jest.fn(),
45
+ soft: jest.fn(),
46
+ notificationSuccess: jest.fn(),
47
+ notificationWarning: jest.fn(),
48
+ notificationError: jest.fn(),
49
+ })
39
50
 
40
51
  it('should be defined', () => {
41
52
  expect(ChatAdapters).toBeDefined()
@@ -47,6 +58,7 @@ describe('ChatAdapters', () => {
47
58
  audio,
48
59
  video,
49
60
  imagePicker,
61
+ haptic,
50
62
  })
51
63
 
52
64
  expect(Clipboard).toEqual(clipboard)
@@ -91,4 +103,37 @@ describe('ChatAdapters', () => {
91
103
  linking.canOpenURL('https://www.google.com')
92
104
  })
93
105
  })
106
+
107
+ describe('haptic adapter', () => {
108
+ it('should configure the haptic adapter', () => {
109
+ ChatAdapters.configure({
110
+ clipboard,
111
+ audio,
112
+ video,
113
+ imagePicker,
114
+ haptic,
115
+ })
116
+
117
+ expect(Haptic).toEqual(haptic)
118
+ })
119
+
120
+ it('should be configured with defaults', () => {
121
+ ChatAdapters.configure({
122
+ clipboard,
123
+ audio,
124
+ video,
125
+ imagePicker,
126
+ })
127
+
128
+ expect(Haptic).toBeDefined()
129
+ expect(Haptic.impactLight).toBeDefined()
130
+ expect(Haptic.impactMedium).toBeDefined()
131
+ expect(Haptic.impactHeavy).toBeDefined()
132
+ expect(Haptic.rigid).toBeDefined()
133
+ expect(Haptic.soft).toBeDefined()
134
+ expect(Haptic.notificationSuccess).toBeDefined()
135
+ expect(Haptic.notificationWarning).toBeDefined()
136
+ expect(Haptic.notificationError).toBeDefined()
137
+ })
138
+ })
94
139
  })
package/src/index.tsx CHANGED
@@ -3,7 +3,7 @@ export { ApiProvider, chatQueryClient, useFocusManager } from './contexts/api_pr
3
3
  export * from './contexts/chat_context'
4
4
  export * from './navigation'
5
5
  export { ScreenLayout } from './navigation/screenLayout'
6
- export { DesignSystemScreen } from './screens'
6
+ export * from './screens'
7
7
  export * from './types'
8
8
  export { platformFontWeightBold, Session, TemporaryDefaultColorsType, Uri } from './utils'
9
9
  export * from './utils/client'
@@ -168,15 +168,20 @@ function FormContent({
168
168
  </TextButton>
169
169
  </View>
170
170
  <View style={styles.toSectionRow}>
171
- {selectedTeams.map(team => (
172
- <View key={team.value.teamId} style={styles.badgeRow}>
173
- <Badge
174
- iconNameRight="general.x"
175
- label={team.name}
176
- onPress={() => removeSelection(team.value.teamId)}
177
- />
178
- </View>
179
- ))}
171
+ {selectedTeams.map(team => {
172
+ const serviceTypeAcronyms = team.serviceTypeAcronyms.join(', ')
173
+ const label = `${team.teamName} | ${serviceTypeAcronyms}`
174
+
175
+ return (
176
+ <View key={team.value.teamId} style={styles.badgeRow}>
177
+ <Badge
178
+ iconNameRight="general.x"
179
+ label={label}
180
+ onPress={() => removeSelection(team.value.teamId)}
181
+ />
182
+ </View>
183
+ )
184
+ })}
180
185
  </View>
181
186
  </View>
182
187
  <Divider />
@@ -4,12 +4,12 @@ import { StyleSheet, View } from 'react-native'
4
4
  import { Badge } from '../../../components'
5
5
  import { useApiGet } from '../../../hooks/use_api'
6
6
  import { GroupResource } from '../../../types/resources/group_resource'
7
- import { ConversationScreenProps } from '../conversations_screen'
7
+ import { ConversationsScreenProps } from '../conversations_screen'
8
8
 
9
9
  export const ChatGroupBadge = ({ rowPaddingHorizontal }: { rowPaddingHorizontal: number }) => {
10
10
  const styles = useStyles({ rowPaddingHorizontal })
11
11
  const navigation = useNavigation()
12
- const route = useRoute<RouteProp<ConversationScreenProps['route']>>()
12
+ const route = useRoute<RouteProp<ConversationsScreenProps['route']>>()
13
13
  const { chat_group_graph_id } = route.params || {}
14
14
  const { data: group } = useApiGet<GroupResource>({
15
15
  url: `/me/groups/${chat_group_graph_id}`,
@@ -5,7 +5,7 @@ import { Heading, TextButton, ToggleButton } from '../../../components'
5
5
  import { useCurrentPersonCache, useTheme } from '../../../hooks'
6
6
  import { useMarkAllRead } from '../../../hooks/use_conversations_actions'
7
7
  import { useCanDisplayGroups } from '../../../hooks/use_groups'
8
- import { ConversationScreenProps } from '../conversations_screen'
8
+ import { ConversationsScreenProps } from '../conversations_screen'
9
9
  import { ChatGroupBadge } from './chat_group_badge'
10
10
 
11
11
  const ROW_PADDING_HORIZONTAL = 16
@@ -22,7 +22,7 @@ export const ListHeaderComponent = () => {
22
22
  const navigation = useNavigation()
23
23
  const canFilterByTeams = useCanDisplayGroups({ source_app_name: 'Services', source_type: 'Team' })
24
24
  const canFilterByGroups = useCanDisplayGroups({ source_app_name: 'Groups', source_type: 'Group' })
25
- const route = useRoute<RouteProp<ConversationScreenProps['route']>>()
25
+ const route = useRoute<RouteProp<ConversationsScreenProps['route']>>()
26
26
  const { chat_group_graph_id, group_source_app_name = '' } = route.params || {}
27
27
  const currentPersonCache = useCurrentPersonCache()
28
28
  const { markAllRead, isPending } = useMarkAllRead()
@@ -11,13 +11,13 @@ import { ListHeaderComponent } from './components/list_header_component'
11
11
  import { AppName } from '../../types/resources/app_name'
12
12
  import { ConversationsJoltEvents } from './components/conversations_jolt_events'
13
13
 
14
- export type ConversationScreenProps = StaticScreenProps<{
14
+ export type ConversationsScreenProps = StaticScreenProps<{
15
15
  title?: string
16
16
  chat_group_graph_id?: GraphId
17
17
  group_source_app_name?: AppName
18
18
  }>
19
19
 
20
- export function ConversationsScreen({ route }: ConversationScreenProps) {
20
+ export function ConversationsScreen({ route }: ConversationsScreenProps) {
21
21
  const navigation = useNavigation()
22
22
  const canCreateConversations = useCanCreateConversations()
23
23
  const styles = useStyles()
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from 'react'
2
2
  import { Alert, Pressable, ScrollView, StyleSheet, View } from 'react-native'
3
3
  import type { ViewStyle } from 'react-native'
4
- import { useTheme } from '../hooks'
4
+ import { useInteractionGhostBackgroundColor, useTheme } from '../hooks'
5
5
  import {
6
6
  Avatar,
7
7
  AvatarGroup,
@@ -27,6 +27,7 @@ import {
27
27
  MAX_FONT_SIZE_MULTIPLIER,
28
28
  platformPressedOpacityStyle,
29
29
  platformFontWeightMedium,
30
+ Haptic,
30
31
  } from '../utils'
31
32
  import BannerPrimitive from '../components/primitive/banner_primitive'
32
33
  import { VideoAttachmentPreview } from '../components/display/video_attachment_preview'
@@ -89,6 +90,7 @@ export function DesignSystemScreen() {
89
90
  <IndicatorsSection />
90
91
  <HeadingTextSection />
91
92
  <PressablesSection />
93
+ <HapticsSection />
92
94
  <ImageIconsSection />
93
95
  <FormControlsSection />
94
96
  <StatusComponentsSection />
@@ -678,6 +680,37 @@ function PressablesSection({ isLast }: SectionProps) {
678
680
  </CollapsableSection>
679
681
  )
680
682
  }
683
+ function HapticsSection({ isLast }: SectionProps) {
684
+ return (
685
+ <CollapsableSection title="Haptics" isLast={isLast}>
686
+ <TextGroup>
687
+ <Text>
688
+ Haptics help communicate changes and interactions in the UI by making them feel physical
689
+ and "weighty". They are a progressive enhancement and shouldn't replace visual feedback.
690
+ </Text>
691
+ </TextGroup>
692
+ <Group title="Impact" description="Communicates that a user interaction is occurring.">
693
+ <Row>
694
+ <HapticButton title="Impact Light" onPress={() => Haptic.impactLight()} />
695
+ <HapticButton title="Impact Medium" onPress={() => Haptic.impactMedium()} />
696
+ <HapticButton title="Impact Heavy" onPress={() => Haptic.impactHeavy()} />
697
+ <HapticButton title="Rigid" onPress={() => Haptic.rigid()} />
698
+ <HapticButton title="Soft" onPress={() => Haptic.soft()} />
699
+ </Row>
700
+ </Group>
701
+ <Group
702
+ title="Notification"
703
+ description="Communicates the result of a user or application action."
704
+ >
705
+ <Row>
706
+ <HapticButton title="Notification Success" onPress={() => Haptic.notificationSuccess()} />
707
+ <HapticButton title="Notification Warning" onPress={() => Haptic.notificationWarning()} />
708
+ <HapticButton title="Notification Error" onPress={() => Haptic.notificationError()} />
709
+ </Row>
710
+ </Group>
711
+ </CollapsableSection>
712
+ )
713
+ }
681
714
 
682
715
  function ImageIconsSection({ isLast }: SectionProps) {
683
716
  const styles = useStyles()
@@ -1143,14 +1176,46 @@ function TextListItem({ label, children }: TextListItemProps) {
1143
1176
  )
1144
1177
  }
1145
1178
 
1179
+ function HapticButton({ title, onPress }: { title: string; onPress: () => void }) {
1180
+ const styles = useStyles()
1181
+
1182
+ return (
1183
+ <Pressable
1184
+ onPress={onPress}
1185
+ style={({ pressed }) => ({
1186
+ ...styles.hapticButton,
1187
+ ...{ opacity: pressed ? 0.5 : 1 },
1188
+ })}
1189
+ >
1190
+ <Text style={styles.hapticButtonText}>{title}</Text>
1191
+ </Pressable>
1192
+ )
1193
+ }
1194
+
1146
1195
  // =================================
1147
1196
  // ====== Styles ===================
1148
1197
  // =================================
1149
1198
 
1150
1199
  const useStyles = () => {
1151
1200
  const { colors } = useTheme()
1201
+ const interactionGhostBackgroundColor = useInteractionGhostBackgroundColor()
1152
1202
 
1153
1203
  return StyleSheet.create({
1204
+ hapticButton: {
1205
+ flexGrow: 1,
1206
+ height: 100,
1207
+ padding: 16,
1208
+ alignItems: 'center',
1209
+ justifyContent: 'center',
1210
+ backgroundColor: interactionGhostBackgroundColor,
1211
+ borderWidth: 1,
1212
+ borderColor: colors.interaction,
1213
+ borderRadius: 8,
1214
+ },
1215
+ hapticButtonText: {
1216
+ textAlign: 'center',
1217
+ color: colors.interaction,
1218
+ },
1154
1219
  scrollView: {
1155
1220
  flex: 1,
1156
1221
  backgroundColor: colors.fillColorNeutral100Inverted,
@@ -1 +1,19 @@
1
1
  export * from './design_system_screen'
2
+ export * from './conversation_details_screen'
3
+ export * from './conversation_screen'
4
+ export * from './conversation_new/conversation_new_screen'
5
+ export * from './conversation_filter_recipients/conversation_filter_recipients_screen'
6
+ export * from './conversation_select_recipients/conversation_select_recipients_screen'
7
+ export * from './message_actions_screen'
8
+ export * from './send_giphy_screen'
9
+ export * from './not_found'
10
+ export * from './reactions_screen'
11
+ export * from './team_conversation_screen'
12
+ export * from './bug_report_screen'
13
+ export * from './conversation/message_read_receipts_screen'
14
+ export * from './conversation_filters_screen'
15
+ export * from './conversation_filters/screen_props'
16
+ export * from './conversation_select_recipients/conversation_select_group_recipients_screen'
17
+ export * from './conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen'
18
+ export * from './attachment_actions/attachment_actions_screen'
19
+ export * from './conversations/conversations_screen'
package/src/utils/date.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { date as formatDate, time as formatTime } from '@planningcenter/datetime-fmt'
1
+ import { date as formatDate } from '@planningcenter/datetime-fmt'
2
2
  import moment from 'moment-timezone'
3
3
 
4
4
  export type DateProps = string | number | Date
@@ -11,7 +11,7 @@ export function formatDatePreview(date?: DateProps) {
11
11
  const isThisWeek = now.isSame(date, 'week')
12
12
  const isThisYear = now.isSame(date, 'year')
13
13
 
14
- if (isToday) return moment(date).format('h:mm a')
14
+ if (isToday) return moment(date).format('h:mma')
15
15
  if (isThisWeek) return formatDate(date, { style: 'relative-short' })
16
16
  if (isThisYear) return formatDate(date, { style: 'abbreviated' })
17
17
 
@@ -58,6 +58,6 @@ export function relativeTime(date: DateProps): string {
58
58
  if (duration.asDays() < 1) {
59
59
  return then.fromNow()
60
60
  } else {
61
- return formatTime(date)
61
+ return moment(date).format('h:mma')
62
62
  }
63
63
  }
@@ -5,6 +5,7 @@ import { ImagePickerAdapter } from './image_picker'
5
5
  import { VideoAdapter } from './video'
6
6
  import { Linking as RNLinking } from 'react-native'
7
7
  import { LinkingAdapter } from './linking'
8
+ import { HapticAdapter } from './haptic'
8
9
 
9
10
  type ChatConfigurations = {
10
11
  clipboard: ClipboardAdapter
@@ -13,6 +14,7 @@ type ChatConfigurations = {
13
14
  imagePicker: ImagePickerAdapter
14
15
  log?: LogAdapter
15
16
  linking?: LinkingAdapter
17
+ haptic?: HapticAdapter
16
18
  }
17
19
 
18
20
  export class ChatAdapters {
@@ -23,6 +25,7 @@ export class ChatAdapters {
23
25
  ImagePicker = configurations.imagePicker
24
26
  Log = configurations.log || new LogAdapter()
25
27
  Linking = configurations.linking || new LinkingAdapter(RNLinking)
28
+ Haptic = configurations.haptic || new HapticAdapter()
26
29
  }
27
30
  }
28
31
 
@@ -69,3 +72,5 @@ export let ImagePicker: ImagePickerAdapter = new ImagePickerAdapter({
69
72
  export let Log: LogAdapter = new LogAdapter()
70
73
 
71
74
  export let Linking: LinkingAdapter = new LinkingAdapter(RNLinking)
75
+
76
+ export let Haptic: HapticAdapter = new HapticAdapter()
@@ -0,0 +1,34 @@
1
+ import { noop } from 'lodash'
2
+
3
+ interface Haptic {
4
+ impactLight: () => void
5
+ impactMedium: () => void
6
+ impactHeavy: () => void
7
+ rigid: () => void
8
+ soft: () => void
9
+ notificationSuccess: () => void
10
+ notificationWarning: () => void
11
+ notificationError: () => void
12
+ }
13
+
14
+ export class HapticAdapter {
15
+ impactLight: () => void
16
+ impactMedium: () => void
17
+ impactHeavy: () => void
18
+ rigid: () => void
19
+ soft: () => void
20
+ notificationSuccess: () => void
21
+ notificationWarning: () => void
22
+ notificationError: () => void
23
+
24
+ constructor(methods?: Haptic) {
25
+ this.impactLight = methods?.impactLight ?? noop
26
+ this.impactMedium = methods?.impactMedium ?? noop
27
+ this.impactHeavy = methods?.impactHeavy ?? noop
28
+ this.rigid = methods?.rigid ?? noop
29
+ this.soft = methods?.soft ?? noop
30
+ this.notificationSuccess = methods?.notificationSuccess ?? noop
31
+ this.notificationWarning = methods?.notificationWarning ?? noop
32
+ this.notificationError = methods?.notificationError ?? noop
33
+ }
34
+ }
@@ -5,3 +5,4 @@ export * from './image_picker'
5
5
  export * from './linking'
6
6
  export * from './log'
7
7
  export * from './video'
8
+ export * from './haptic'