@planningcenter/chat-react-native 3.2.0-rc.15 → 3.2.0-rc.17

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 (58) hide show
  1. package/build/contexts/api_provider.d.ts +1 -1
  2. package/build/contexts/api_provider.d.ts.map +1 -1
  3. package/build/contexts/api_provider.js +3 -3
  4. package/build/contexts/api_provider.js.map +1 -1
  5. package/build/contexts/chat_context.d.ts +4 -4
  6. package/build/contexts/chat_context.d.ts.map +1 -1
  7. package/build/contexts/chat_context.js +3 -3
  8. package/build/contexts/chat_context.js.map +1 -1
  9. package/build/hooks/use_api.d.ts.map +1 -1
  10. package/build/hooks/use_api.js +5 -0
  11. package/build/hooks/use_api.js.map +1 -1
  12. package/build/hooks/use_api_client.d.ts.map +1 -1
  13. package/build/hooks/use_api_client.js +5 -3
  14. package/build/hooks/use_api_client.js.map +1 -1
  15. package/build/hooks/use_jolt.d.ts.map +1 -1
  16. package/build/hooks/use_jolt.js +15 -22
  17. package/build/hooks/use_jolt.js.map +1 -1
  18. package/build/hooks/use_message_create.js +2 -2
  19. package/build/hooks/use_message_create.js.map +1 -1
  20. package/build/hooks/use_suspense_api.d.ts.map +1 -1
  21. package/build/hooks/use_suspense_api.js +5 -0
  22. package/build/hooks/use_suspense_api.js.map +1 -1
  23. package/build/index.d.ts +2 -2
  24. package/build/index.d.ts.map +1 -1
  25. package/build/index.js +2 -2
  26. package/build/index.js.map +1 -1
  27. package/build/types/resources/oauth_token.d.ts +4 -4
  28. package/build/types/resources/oauth_token.d.ts.map +1 -1
  29. package/build/types/resources/oauth_token.js.map +1 -1
  30. package/build/utils/client/client.d.ts +4 -8
  31. package/build/utils/client/client.d.ts.map +1 -1
  32. package/build/utils/client/client.js +10 -9
  33. package/build/utils/client/client.js.map +1 -1
  34. package/build/utils/session.d.ts +6 -2
  35. package/build/utils/session.d.ts.map +1 -1
  36. package/build/utils/session.js +6 -1
  37. package/build/utils/session.js.map +1 -1
  38. package/build/utils/uri.d.ts +10 -2
  39. package/build/utils/uri.d.ts.map +1 -1
  40. package/build/utils/uri.js +24 -6
  41. package/build/utils/uri.js.map +1 -1
  42. package/package.json +2 -2
  43. package/src/__tests__/hooks/useTheme.tsx +1 -1
  44. package/src/__tests__/{client.ts → utils/client.ts} +7 -115
  45. package/src/__tests__/{session.ts → utils/session.ts} +4 -4
  46. package/src/__tests__/utils/uri.ts +107 -0
  47. package/src/contexts/api_provider.tsx +3 -3
  48. package/src/contexts/chat_context.tsx +7 -7
  49. package/src/hooks/use_api.ts +8 -2
  50. package/src/hooks/use_api_client.ts +7 -3
  51. package/src/hooks/use_jolt.ts +18 -23
  52. package/src/hooks/use_message_create.ts +2 -2
  53. package/src/hooks/use_suspense_api.ts +6 -0
  54. package/src/index.tsx +2 -1
  55. package/src/types/resources/oauth_token.ts +4 -4
  56. package/src/utils/client/client.ts +13 -13
  57. package/src/utils/session.ts +10 -4
  58. package/src/utils/uri.ts +30 -6
@@ -8,10 +8,10 @@ import {
8
8
  JoltSubscription,
9
9
  } from '@planningcenter/jolt-client/dist/types/JoltSubscription'
10
10
  import { useQuery, useQueryClient, useSuspenseQuery } from '@tanstack/react-query'
11
- import { useEffect, useMemo, useState } from 'react'
11
+ import { useCallback, useEffect, useMemo, useState } from 'react'
12
12
  import { useChatContext } from '../contexts/chat_context'
13
13
  import { ApiResource } from '../types'
14
- import { Client } from '../utils'
14
+ import { Client, Uri } from '../utils'
15
15
 
16
16
  interface JoltResponse {
17
17
  type: 'JoltToken'
@@ -22,28 +22,18 @@ interface JoltResponse {
22
22
  export const useJoltClient = (): JoltClient | undefined => {
23
23
  const { session } = useChatContext()
24
24
  const queryClient = useQueryClient()
25
+ const uri = useMemo(() => new Uri({ session }), [session])
25
26
  const apiClient = useMemo(
26
- // Client that does not relay 401 errors
27
- () => new Client({ app: 'chat', session, version: '2018-11-01' }),
28
- [session]
27
+ () =>
28
+ new Client({
29
+ root: uri.api(`/chat/v2`),
30
+ defaultHeaders: uri.headers,
31
+ version: '2018-11-01',
32
+ }),
33
+ [uri]
29
34
  )
30
35
 
31
- const { data: joltToken } = useSuspenseQuery<ApiResource<JoltResponse>>({
32
- queryKey: ['jolt-token'],
33
- queryFn: () => {
34
- return apiClient.post({
35
- url: '/me/jolt_authorize',
36
- data: {
37
- data: {
38
- type: 'JoltToken',
39
- attributes: {},
40
- },
41
- },
42
- })
43
- },
44
- })
45
-
46
- const fetchJoltToken = async () => {
36
+ const fetchJoltToken = useCallback(async () => {
47
37
  return apiClient.post<ApiResource<JoltResponse>>({
48
38
  url: '/me/jolt_authorize',
49
39
  data: {
@@ -53,11 +43,16 @@ export const useJoltClient = (): JoltClient | undefined => {
53
43
  },
54
44
  },
55
45
  })
56
- }
46
+ }, [apiClient])
47
+
48
+ const { data: joltToken } = useSuspenseQuery<ApiResource<JoltResponse>>({
49
+ queryKey: ['jolt-token'],
50
+ queryFn: fetchJoltToken,
51
+ })
57
52
 
58
53
  const fetchAuthTokenFn: FetchAuthToken = () => {
59
54
  return queryClient.fetchQuery({
60
- queryKey: ['jolt-token'],
55
+ queryKey: ['jolt-auth-token'],
61
56
  queryFn: () => fetchJoltToken().then(res => res.data.id),
62
57
  })
63
58
  }
@@ -2,7 +2,7 @@ import { InfiniteData, useMutation } from '@tanstack/react-query'
2
2
  import { getMessagesQueryKey, getMessagesRequestArgs } from './use_conversation_messages'
3
3
  import { useApiClient } from './use_api_client'
4
4
  import { ApiCollection, ApiResource, MessageResource } from '../types'
5
- import { queryClient } from '../contexts/api_provider'
5
+ import { chatQueryClient } from '../contexts/api_provider'
6
6
  import { updateOrCreateRecordInPagesData } from '../utils'
7
7
  import { DenormalizedAttachmentResourceForCreate } from '../types/resources/denormalized_attachment_resource'
8
8
 
@@ -42,7 +42,7 @@ export function useMessageCreate({ conversationId }: Props) {
42
42
  type QueryData = InfiniteData<ApiCollection<MessageResource>>
43
43
  const queryKey = getMessagesQueryKey({ conversation_id: conversationId })
44
44
 
45
- queryClient.setQueryData<QueryData>(queryKey, data =>
45
+ chatQueryClient.setQueryData<QueryData>(queryKey, data =>
46
46
  updateOrCreateRecordInPagesData({
47
47
  data,
48
48
  record: updatedMessage,
@@ -16,9 +16,15 @@ export const useSuspenseGet = <T extends ResourceObject | ResourceObject[]>(
16
16
  args: SuspenseGetOptions
17
17
  ) => {
18
18
  type Resource = ApiResource<T>
19
+ const apiClient = useApiClient()
19
20
 
20
21
  const { data, ...query } = useSuspenseQuery<Resource, Response>({
21
22
  queryKey: getRequestQueryKey(args),
23
+ queryFn: ({ queryKey }) => {
24
+ const [url, d, headers, app = 'chat'] = queryKey as RequestQueryKey
25
+
26
+ return apiClient[app].get({ url, data: d, headers }) as Promise<Resource>
27
+ },
22
28
  })
23
29
 
24
30
  return { ...data, ...query }
package/src/index.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from './contexts/chat_context'
2
- export { ApiProvider } from './contexts/api_provider'
2
+ export { ApiProvider, chatQueryClient } from './contexts/api_provider'
3
3
  export { DesignSystemScreen } from './screens'
4
4
  export * from './navigation'
5
5
  export * from './types'
@@ -10,5 +10,6 @@ export {
10
10
  ChatAdapters,
11
11
  ClipboardAdapter,
12
12
  Session,
13
+ Uri,
13
14
  platformFontWeightBold,
14
15
  } from './utils'
@@ -1,8 +1,8 @@
1
1
  export type OAuthToken = {
2
- token_type: any
3
- access_token: any
2
+ token_type: string
3
+ access_token: string
4
4
  created_at: number
5
- expires_in: any
5
+ expires_in: number
6
6
  scope: string
7
- refresh_token: any
7
+ refresh_token: string
8
8
  }
@@ -1,6 +1,4 @@
1
1
  import { ApiCollection, ApiError, ApiResource } from '../../types'
2
- import { Session } from '../session'
3
- import { Uri } from '../uri'
4
2
  import {
5
3
  concatRecords,
6
4
  ensureNoQueryParamsInDev,
@@ -22,28 +20,27 @@ type ClientArgs = {
22
20
  version: string
23
21
  defaultHeaders?: Record<string, string>
24
22
  onUnauthorizedResponse?: OnUnauthorizedResponse
25
- session: Session
26
- app: string
23
+ root?: string
27
24
  }
28
25
 
29
26
  export class Client {
30
27
  version: string = ''
31
28
  defaultHeaders: Record<string, string> = {}
32
- uri: Uri
33
29
  onUnauthorizedResponse?: OnUnauthorizedResponse
30
+ root?: string
34
31
 
35
- constructor({ version, defaultHeaders = {}, session, app, onUnauthorizedResponse }: ClientArgs) {
32
+ constructor({ version, defaultHeaders = {}, onUnauthorizedResponse, root }: ClientArgs) {
36
33
  this.version = version
37
- this.uri = new Uri({ session, app })
38
34
  this.defaultHeaders = defaultHeaders
39
35
  this.onUnauthorizedResponse = onUnauthorizedResponse
36
+ this.root = root
40
37
  }
41
38
 
42
39
  async get<T extends ApiCollection | ApiResource>(args: GetRequest): Promise<T> {
43
40
  const { walk, ...data } = args.data
44
41
  const isWalking = Boolean(walk)
45
42
  const headers = { ...this.headers, ...args.headers }
46
- const url = this.uri.appUrl(args.url)
43
+ const url = this.appUrl(args.url)
47
44
 
48
45
  await throwErrorIfQueryParams(url)
49
46
 
@@ -54,7 +51,7 @@ export class Client {
54
51
  data: d = { fields: {} },
55
52
  acc = { data: [], included: [], meta: {}, links: {} },
56
53
  ...options
57
- }: WalkRequest): Promise<ApiCollection | ApiResource> => {
54
+ }: WalkRequest): Promise<T> => {
58
55
  return makeRequest({
59
56
  action: 'GET',
60
57
  data: d,
@@ -84,7 +81,7 @@ export class Client {
84
81
 
85
82
  async patch<T extends ApiCollection | ApiResource>(args: PatchRequest): Promise<T> {
86
83
  const headers = { ...this.headers, ...args.headers }
87
- const url = this.uri.appUrl(args.url)
84
+ const url = this.appUrl(args.url)
88
85
 
89
86
  const requestArgs: MakeRequestArgs = { data: args.data, url, action: 'PATCH', headers }
90
87
 
@@ -95,7 +92,7 @@ export class Client {
95
92
 
96
93
  async post<T extends ApiCollection | ApiResource>(args: PostRequest): Promise<T> {
97
94
  const headers = { ...this.headers, ...args.headers }
98
- const url = this.uri.appUrl(args.url)
95
+ const url = this.appUrl(args.url)
99
96
 
100
97
  const requestArgs: MakeRequestArgs = { ...args, data: args.data, url, action: 'POST', headers }
101
98
 
@@ -106,7 +103,7 @@ export class Client {
106
103
 
107
104
  async delete(args: DeleteRequest) {
108
105
  const headers = { ...this.headers, ...args.headers }
109
- const url = this.uri.appUrl(args.url)
106
+ const url = this.appUrl(args.url)
110
107
 
111
108
  const requestArgs: MakeRequestArgs = { url, action: 'DELETE', headers }
112
109
 
@@ -133,12 +130,15 @@ export class Client {
133
130
  }
134
131
  }
135
132
 
133
+ appUrl(url: string) {
134
+ return `${this.root}${url}`
135
+ }
136
+
136
137
  get headers() {
137
138
  return {
138
139
  Accept: 'application/vnd.api+json',
139
140
  'Content-Type': 'application/json',
140
141
  'X-PCO-API-Version': this.version,
141
- ...this.uri.headers,
142
142
  ...this.defaultHeaders,
143
143
  }
144
144
  }
@@ -1,28 +1,34 @@
1
1
  import { OAuthToken } from '../types'
2
2
 
3
3
  export type ENV = 'production' | 'staging' | 'development'
4
-
4
+ export type OauthType = 'OAuth' | 'ChurchCenterOauth'
5
5
  export type PartialToken = Pick<OAuthToken, 'access_token'> & Partial<OAuthToken>
6
- export type SessionProps<T = PartialToken> = { env?: ENV; token?: T }
6
+ export type SessionProps<T extends PartialToken> = { env?: ENV; token?: T; type?: OauthType }
7
7
 
8
8
  /**
9
9
  * Session class to track the environment and token
10
10
  * Not intended to make network requests or handle authentication
11
11
  */
12
- export class Session<T = PartialToken> {
12
+ export class Session<T extends PartialToken = PartialToken> {
13
13
  env: ENV
14
14
  token: T | undefined
15
+ type: OauthType
15
16
 
16
17
  constructor(props?: SessionProps<T>) {
17
- const { env = 'production', token } = props || {}
18
+ const { env = 'production', token, type } = props || {}
18
19
  this.env = env
19
20
  this.token = token
21
+ this.type = type || 'OAuth'
20
22
  }
21
23
 
22
24
  get isAuthenticated() {
23
25
  return Boolean(this.token)
24
26
  }
25
27
 
28
+ get isChurchCenterToken() {
29
+ return this.type === 'ChurchCenterOauth'
30
+ }
31
+
26
32
  toString() {
27
33
  return JSON.stringify({ env: this.env, token: this.token })
28
34
  }
package/src/utils/uri.ts CHANGED
@@ -7,13 +7,16 @@ const systemVersion = DeviceInfo.getSystemVersion()
7
7
  const readableVersion = DeviceInfo.getReadableVersion()
8
8
  const appName = DeviceInfo.getApplicationName()
9
9
 
10
+ type Graph = 'churchcenter' | 'planningcenter'
10
11
  export class Uri {
11
12
  session: Session
13
+ graph: Graph = 'planningcenter'
12
14
  app?: string
13
15
 
14
- constructor({ session, app }: { session: Session; app?: string }) {
16
+ constructor({ session, app, graph }: { session: Session; app?: string; graph?: Graph }) {
15
17
  this.session = session
16
18
  this.app = app
19
+ this.graph = graph || 'planningcenter'
17
20
  }
18
21
 
19
22
  get schema() {
@@ -25,18 +28,39 @@ export class Uri {
25
28
  }
26
29
 
27
30
  get host() {
31
+ return `${this.subdomain}.${this.domain}.${this.tld}`
32
+ }
33
+
34
+ get subdomain() {
28
35
  switch (this.env) {
29
- case 'production':
30
- return 'api.planningcenteronline.com'
31
36
  case 'staging':
32
- return 'api-staging.planningcenteronline.com'
37
+ return this.isChurchCenter ? 'api.staging' : 'api-staging'
38
+ default:
39
+ return 'api'
40
+ }
41
+ }
42
+
43
+ get domain(): 'pco' | 'planningcenteronline' | 'churchcenter' {
44
+ if (this.isChurchCenter) {
45
+ return 'churchcenter'
46
+ }
47
+
48
+ return this.env === 'development' ? 'pco' : 'planningcenteronline'
49
+ }
50
+
51
+ get tld() {
52
+ switch (this.env) {
33
53
  case 'development':
34
- return 'api.pco.test'
54
+ return 'test'
35
55
  default:
36
- return 'api.planningcenteronline.com'
56
+ return 'com'
37
57
  }
38
58
  }
39
59
 
60
+ get isChurchCenter() {
61
+ return this.session.isChurchCenterToken
62
+ }
63
+
40
64
  get env() {
41
65
  return this.session?.env || 'production'
42
66
  }