@planningcenter/chat-react-native 1.6.0 → 1.6.1-qa-27.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.
- package/build/components/error_boundary.d.ts +1 -1
- package/build/contexts/api_provider.d.ts +1 -5
- package/build/contexts/api_provider.d.ts.map +1 -1
- package/build/contexts/api_provider.js +19 -7
- package/build/contexts/api_provider.js.map +1 -1
- package/build/contexts/chat_context.d.ts +11 -9
- package/build/contexts/chat_context.d.ts.map +1 -1
- package/build/contexts/chat_context.js +13 -37
- package/build/contexts/chat_context.js.map +1 -1
- package/build/navigation/screenLayout.d.ts.map +1 -1
- package/build/navigation/screenLayout.js +8 -5
- package/build/navigation/screenLayout.js.map +1 -1
- package/build/utils/theme.d.ts +1 -1
- package/build/utils/theme.d.ts.map +1 -1
- package/build/utils/theme.js +5 -1
- package/build/utils/theme.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/hooks/useTheme.tsx +39 -5
- package/src/contexts/api_provider.tsx +25 -11
- package/src/contexts/chat_context.tsx +21 -54
- package/src/navigation/screenLayout.tsx +10 -7
- package/src/utils/theme.ts +7 -2
|
@@ -8,7 +8,7 @@ declare class ErrorBoundary extends React.Component<PropsWithChildren<{
|
|
|
8
8
|
};
|
|
9
9
|
componentDidCatch(error: any): void;
|
|
10
10
|
handleError(error: any): void;
|
|
11
|
-
render(): string | number | boolean |
|
|
11
|
+
render(): string | number | boolean | React.JSX.Element | Iterable<React.ReactNode> | null | undefined;
|
|
12
12
|
}
|
|
13
13
|
export default ErrorBoundary;
|
|
14
14
|
//# sourceMappingURL=error_boundary.d.ts.map
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { QueryClient } from '@tanstack/react-query';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { ViewProps } from 'react-native';
|
|
4
|
-
import { Client } from '../utils';
|
|
5
4
|
export declare const queryClient: QueryClient;
|
|
6
|
-
export declare function ApiProvider({ children
|
|
7
|
-
client: Client;
|
|
8
|
-
sessionChanged: boolean;
|
|
9
|
-
}): React.JSX.Element;
|
|
5
|
+
export declare function ApiProvider({ children }: ViewProps): React.JSX.Element;
|
|
10
6
|
//# sourceMappingURL=api_provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api_provider.d.ts","sourceRoot":"","sources":["../../src/contexts/api_provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiC,MAAM,uBAAuB,CAAA;AAClF,OAAO,
|
|
1
|
+
{"version":3,"file":"api_provider.d.ts","sourceRoot":"","sources":["../../src/contexts/api_provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiC,MAAM,uBAAuB,CAAA;AAClF,OAAO,KAAwC,MAAM,OAAO,CAAA;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAiBxC,eAAO,MAAM,WAAW,aAOtB,CAAA;AAEF,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,qBAalD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
2
|
-
import React, { useEffect } from 'react';
|
|
2
|
+
import React, { useContext, useEffect, useRef } from 'react';
|
|
3
|
+
import { ChatContext } from './chat_context';
|
|
3
4
|
let apiClient;
|
|
4
5
|
const defaultQueryFn = ({ queryKey }) => {
|
|
5
6
|
if (!apiClient) {
|
|
@@ -16,16 +17,27 @@ export const queryClient = new QueryClient({
|
|
|
16
17
|
},
|
|
17
18
|
},
|
|
18
19
|
});
|
|
19
|
-
export function ApiProvider({ children
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// TODO: CREATE CALLBACK TO INVALIDATE QUERIES
|
|
20
|
+
export function ApiProvider({ children }) {
|
|
21
|
+
const { token, env, client } = useContext(ChatContext);
|
|
22
|
+
const sessionChanged = useSessionChanged({ token, env });
|
|
23
|
+
apiClient = client;
|
|
24
24
|
useEffect(() => {
|
|
25
25
|
if (!sessionChanged)
|
|
26
26
|
return;
|
|
27
|
-
queryClient.
|
|
27
|
+
queryClient.clear();
|
|
28
28
|
}, [sessionChanged]);
|
|
29
29
|
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
|
30
30
|
}
|
|
31
|
+
function useSessionChanged(value) {
|
|
32
|
+
const { token: newToken, env: newEnv } = value;
|
|
33
|
+
const { token: prevToken, env: prevEnv } = usePrevious(value);
|
|
34
|
+
return Boolean(prevToken && newToken !== prevToken) || Boolean(prevEnv && newEnv !== prevEnv);
|
|
35
|
+
}
|
|
36
|
+
function usePrevious(value) {
|
|
37
|
+
const ref = useRef(value);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
ref.current = value;
|
|
40
|
+
}, [value]);
|
|
41
|
+
return ref.current;
|
|
42
|
+
}
|
|
31
43
|
//# sourceMappingURL=api_provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api_provider.js","sourceRoot":"","sources":["../../src/contexts/api_provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAY,MAAM,uBAAuB,CAAA;AAClF,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"api_provider.js","sourceRoot":"","sources":["../../src/contexts/api_provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAY,MAAM,uBAAuB,CAAA;AAClF,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAI5D,OAAO,EAAE,WAAW,EAAoB,MAAM,gBAAgB,CAAA;AAE9D,IAAI,SAA6B,CAAA;AAEjC,MAAM,cAAc,GAAG,CAAC,EAAE,QAAQ,EAA0B,EAAE,EAAE;IAC9D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;IACrC,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAe,CAAA;IAEtC,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AAC5B,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC;IACzC,cAAc,EAAE;QACd,OAAO,EAAE;YACP,OAAO,EAAE,cAAc;YACvB,KAAK,EAAE,CAAC;SACT;KACF;CACF,CAAC,CAAA;AAEF,MAAM,UAAU,WAAW,CAAC,EAAE,QAAQ,EAAa;IACjD,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACtD,MAAM,cAAc,GAAG,iBAAiB,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;IAExD,SAAS,GAAG,MAAM,CAAA;IAElB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,cAAc;YAAE,OAAM;QAE3B,WAAW,CAAC,KAAK,EAAE,CAAA;IACrB,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAA;IAEpB,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,CAAA;AACnF,CAAC;AAED,SAAS,iBAAiB,CAAC,KAA8C;IACvE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IAC9C,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,WAAW,CAAe,KAAK,CAAC,CAAA;IAE3E,OAAO,OAAO,CAAC,SAAS,IAAI,QAAQ,KAAK,SAAS,CAAC,IAAI,OAAO,CAAC,OAAO,IAAI,MAAM,KAAK,OAAO,CAAC,CAAA;AAC/F,CAAC;AAED,SAAS,WAAW,CAAI,KAAK;IAC3B,MAAM,GAAG,GAAG,MAAM,CAAI,KAAK,CAAC,CAAA;IAE5B,SAAS,CAAC,GAAG,EAAE;QACb,GAAG,CAAC,OAAO,GAAG,KAAK,CAAA;IACrB,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,OAAO,GAAG,CAAC,OAAO,CAAA;AACpB,CAAC","sourcesContent":["import { QueryClient, QueryClientProvider, QueryKey } from '@tanstack/react-query'\nimport React, { useContext, useEffect, useRef } from 'react'\nimport { ViewProps } from 'react-native'\nimport { Client } from '../utils'\nimport { GetRequest } from '../utils/client/types'\nimport { ChatContext, ChatContextValue } from './chat_context'\n\nlet apiClient: Client | undefined\n\nconst defaultQueryFn = ({ queryKey }: { queryKey: QueryKey }) => {\n if (!apiClient) {\n throw new Error('No token present')\n }\n\n const data = queryKey[0] as GetRequest\n\n return apiClient.get(data)\n}\n\nexport const queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n queryFn: defaultQueryFn,\n retry: 3,\n },\n },\n})\n\nexport function ApiProvider({ children }: ViewProps) {\n const { token, env, client } = useContext(ChatContext)\n const sessionChanged = useSessionChanged({ token, env })\n\n apiClient = client\n\n useEffect(() => {\n if (!sessionChanged) return\n\n queryClient.clear()\n }, [sessionChanged])\n\n return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>\n}\n\nfunction useSessionChanged(value: Pick<ChatContextValue, 'token' | 'env'>): boolean {\n const { token: newToken, env: newEnv } = value\n const { token: prevToken, env: prevEnv } = usePrevious<typeof value>(value)\n\n return Boolean(prevToken && newToken !== prevToken) || Boolean(prevEnv && newEnv !== prevEnv)\n}\n\nfunction usePrevious<T>(value) {\n const ref = useRef<T>(value)\n\n useEffect(() => {\n ref.current = value\n }, [value])\n\n return ref.current\n}\n"]}
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ColorSchemeName } from 'react-native';
|
|
3
3
|
import { DeepPartial, OAuthToken } from '../types';
|
|
4
|
-
import { DefaultTheme } from '../utils/theme';
|
|
5
4
|
import { Client, ENV } from '../utils';
|
|
6
|
-
|
|
5
|
+
import { ChatTheme, DefaultTheme } from '../utils/theme';
|
|
6
|
+
export type ChatContextValue = {
|
|
7
7
|
token?: OAuthToken;
|
|
8
8
|
onTokenExpired: () => void;
|
|
9
|
-
theme:
|
|
9
|
+
theme: ChatTheme;
|
|
10
10
|
env?: ENV;
|
|
11
11
|
client: Client;
|
|
12
12
|
};
|
|
13
|
+
export interface ChatProviderProps extends Omit<ChatContextValue, 'client' | 'theme'> {
|
|
14
|
+
theme: CreateChatThemeProps;
|
|
15
|
+
}
|
|
13
16
|
export declare const ChatContext: React.Context<ChatContextValue>;
|
|
14
|
-
export declare function ChatProvider({ children, value
|
|
17
|
+
export declare function ChatProvider({ children, value }: {
|
|
15
18
|
children: any;
|
|
16
|
-
value:
|
|
17
|
-
}): React.JSX.Element
|
|
18
|
-
interface CreateChatThemeProps {
|
|
19
|
+
value: ChatProviderProps;
|
|
20
|
+
}): React.JSX.Element;
|
|
21
|
+
export interface CreateChatThemeProps {
|
|
19
22
|
theme?: DeepPartial<DefaultTheme>;
|
|
20
23
|
colorScheme?: ColorSchemeName;
|
|
21
24
|
}
|
|
22
|
-
export declare const useCreateChatTheme: ({ theme: customTheme, colorScheme: appColorScheme, }: CreateChatThemeProps) =>
|
|
23
|
-
export {};
|
|
25
|
+
export declare const useCreateChatTheme: ({ theme: customTheme, colorScheme: appColorScheme, }: CreateChatThemeProps) => ChatTheme;
|
|
24
26
|
//# sourceMappingURL=chat_context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat_context.d.ts","sourceRoot":"","sources":["../../src/contexts/chat_context.tsx"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"chat_context.d.ts","sourceRoot":"","sources":["../../src/contexts/chat_context.tsx"],"names":[],"mappings":"AACA,OAAO,KAAiC,MAAM,OAAO,CAAA;AACrD,OAAO,EAAE,eAAe,EAAkB,MAAM,cAAc,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,GAAG,EAAW,MAAM,UAAU,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAgB,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAEtE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,KAAK,EAAE,SAAS,CAAA;IAChB,GAAG,CAAC,EAAE,GAAG,CAAA;IACT,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,OAAO,CAAC;IACnF,KAAK,EAAE,oBAAoB,CAAA;CAC5B;AASD,eAAO,MAAM,WAAW,iCAMtB,CAAA;AAEF,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;IAAE,QAAQ,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,qBAwB5F;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAA;IACjC,WAAW,CAAC,EAAE,eAAe,CAAA;CAC9B;AAED,eAAO,MAAM,kBAAkB,yDAG5B,oBAAoB,KAAG,SAYzB,CAAA"}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { merge } from 'lodash';
|
|
2
|
-
import React, { createContext,
|
|
2
|
+
import React, { createContext, useMemo } from 'react';
|
|
3
3
|
import { useColorScheme } from 'react-native';
|
|
4
|
-
import { defaultTheme } from '../utils/theme';
|
|
5
|
-
import { aliasTokensColorMap } from '../vendor/tapestry/alias_tokens_color_map';
|
|
6
|
-
import { ApiProvider } from './api_provider';
|
|
7
4
|
import { Client, Session } from '../utils';
|
|
5
|
+
import { defaultTheme } from '../utils/theme';
|
|
8
6
|
const defaultChatClient = new Client({
|
|
9
7
|
app: 'chat',
|
|
10
8
|
session: new Session(),
|
|
@@ -12,15 +10,15 @@ const defaultChatClient = new Client({
|
|
|
12
10
|
onTokenExpired: () => null,
|
|
13
11
|
});
|
|
14
12
|
export const ChatContext = createContext({
|
|
15
|
-
theme:
|
|
13
|
+
theme: defaultTheme('light'),
|
|
16
14
|
token: undefined,
|
|
17
15
|
env: undefined,
|
|
18
16
|
onTokenExpired: () => { },
|
|
19
17
|
client: defaultChatClient,
|
|
20
18
|
});
|
|
21
|
-
export function ChatProvider({ children, value
|
|
19
|
+
export function ChatProvider({ children, value }) {
|
|
22
20
|
const { env, token, onTokenExpired } = value;
|
|
23
|
-
const theme = useCreateChatTheme(value.theme);
|
|
21
|
+
const theme = useCreateChatTheme(value.theme || {});
|
|
24
22
|
const session = useMemo(() => new Session({ token, env }), [env, token]);
|
|
25
23
|
const client = useMemo(() => new Client({
|
|
26
24
|
app: 'chat',
|
|
@@ -28,7 +26,6 @@ export function ChatProvider({ children, value, }) {
|
|
|
28
26
|
version: '2018-11-01',
|
|
29
27
|
onTokenExpired,
|
|
30
28
|
}), [onTokenExpired, session]);
|
|
31
|
-
const sessionChanged = useSessionChanged({ token, env });
|
|
32
29
|
const contextValue = {
|
|
33
30
|
env,
|
|
34
31
|
token,
|
|
@@ -36,38 +33,17 @@ export function ChatProvider({ children, value, }) {
|
|
|
36
33
|
theme,
|
|
37
34
|
client,
|
|
38
35
|
};
|
|
39
|
-
|
|
40
|
-
return null;
|
|
41
|
-
return (<ChatContext.Provider value={contextValue}>
|
|
42
|
-
<ApiProvider sessionChanged={sessionChanged} client={client}>
|
|
43
|
-
{children}
|
|
44
|
-
</ApiProvider>
|
|
45
|
-
</ChatContext.Provider>);
|
|
46
|
-
}
|
|
47
|
-
function useSessionChanged(value) {
|
|
48
|
-
const { token: newToken, env: newEnv } = value;
|
|
49
|
-
const { token: prevToken, env: prevEnv } = usePrevious(value);
|
|
50
|
-
return Boolean(prevToken && newToken !== prevToken) || Boolean(prevEnv && newEnv !== prevEnv);
|
|
51
|
-
}
|
|
52
|
-
function usePrevious(value) {
|
|
53
|
-
const ref = useRef(value);
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
ref.current = value;
|
|
56
|
-
}, [value]);
|
|
57
|
-
return ref.current;
|
|
36
|
+
return <ChatContext.Provider value={contextValue}>{children}</ChatContext.Provider>;
|
|
58
37
|
}
|
|
59
38
|
export const useCreateChatTheme = ({ theme: customTheme = {}, colorScheme: appColorScheme, }) => {
|
|
60
39
|
const internalColorScheme = useColorScheme() || 'light';
|
|
61
40
|
const colorScheme = appColorScheme || internalColorScheme;
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
colors
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
};
|
|
70
|
-
}, [colorScheme, customTheme]);
|
|
71
|
-
return memoizedTheme;
|
|
41
|
+
const theme = {
|
|
42
|
+
...merge({}, defaultTheme(colorScheme), customTheme),
|
|
43
|
+
colors: {
|
|
44
|
+
...merge({}, defaultTheme(colorScheme).colors, customTheme?.colors),
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
return theme;
|
|
72
48
|
};
|
|
73
49
|
//# sourceMappingURL=chat_context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat_context.js","sourceRoot":"","sources":["../../src/contexts/chat_context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"chat_context.js","sourceRoot":"","sources":["../../src/contexts/chat_context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AACrD,OAAO,EAAmB,cAAc,EAAE,MAAM,cAAc,CAAA;AAE9D,OAAO,EAAE,MAAM,EAAO,OAAO,EAAE,MAAM,UAAU,CAAA;AAC/C,OAAO,EAAa,YAAY,EAAgB,MAAM,gBAAgB,CAAA;AActE,MAAM,iBAAiB,GAAG,IAAI,MAAM,CAAC;IACnC,GAAG,EAAE,MAAM;IACX,OAAO,EAAE,IAAI,OAAO,EAAE;IACtB,OAAO,EAAE,YAAY;IACrB,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI;CAC3B,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAmB;IACzD,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC;IAC5B,KAAK,EAAE,SAAS;IAChB,GAAG,EAAE,SAAS;IACd,cAAc,EAAE,GAAG,EAAE,GAAE,CAAC;IACxB,MAAM,EAAE,iBAAiB;CAC1B,CAAC,CAAA;AAEF,MAAM,UAAU,YAAY,CAAC,EAAE,QAAQ,EAAE,KAAK,EAA+C;IAC3F,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,KAAK,CAAA;IAC5C,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;IACnD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,OAAO,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;IACxE,MAAM,MAAM,GAAG,OAAO,CACpB,GAAG,EAAE,CACH,IAAI,MAAM,CAAC;QACT,GAAG,EAAE,MAAM;QACX,OAAO;QACP,OAAO,EAAE,YAAY;QACrB,cAAc;KACf,CAAC,EACJ,CAAC,cAAc,EAAE,OAAO,CAAC,CAC1B,CAAA;IAED,MAAM,YAAY,GAAqB;QACrC,GAAG;QACH,KAAK;QACL,cAAc;QACd,KAAK;QACL,MAAM;KACP,CAAA;IAED,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;AACrF,CAAC;AAOD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EACjC,KAAK,EAAE,WAAW,GAAG,EAAE,EACvB,WAAW,EAAE,cAAc,GACN,EAAa,EAAE;IACpC,MAAM,mBAAmB,GAAG,cAAc,EAAE,IAAI,OAAO,CAAA;IACvD,MAAM,WAAW,GAAG,cAAc,IAAI,mBAAmB,CAAA;IAEzD,MAAM,KAAK,GAAG;QACZ,GAAG,KAAK,CAAC,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;QACpD,MAAM,EAAE;YACN,GAAG,KAAK,CAAC,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC;SACpE;KACF,CAAA;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA","sourcesContent":["import { merge } from 'lodash'\nimport React, { createContext, useMemo } from 'react'\nimport { ColorSchemeName, useColorScheme } from 'react-native'\nimport { DeepPartial, OAuthToken } from '../types'\nimport { Client, ENV, Session } from '../utils'\nimport { ChatTheme, defaultTheme, DefaultTheme } from '../utils/theme'\n\nexport type ChatContextValue = {\n token?: OAuthToken\n onTokenExpired: () => void\n theme: ChatTheme\n env?: ENV\n client: Client\n}\n\nexport interface ChatProviderProps extends Omit<ChatContextValue, 'client' | 'theme'> {\n theme: CreateChatThemeProps\n}\n\nconst defaultChatClient = new Client({\n app: 'chat',\n session: new Session(),\n version: '2018-11-01',\n onTokenExpired: () => null,\n})\n\nexport const ChatContext = createContext<ChatContextValue>({\n theme: defaultTheme('light'),\n token: undefined,\n env: undefined,\n onTokenExpired: () => {},\n client: defaultChatClient,\n})\n\nexport function ChatProvider({ children, value }: { children: any; value: ChatProviderProps }) {\n const { env, token, onTokenExpired } = value\n const theme = useCreateChatTheme(value.theme || {})\n const session = useMemo(() => new Session({ token, env }), [env, token])\n const client = useMemo(\n () =>\n new Client({\n app: 'chat',\n session,\n version: '2018-11-01',\n onTokenExpired,\n }),\n [onTokenExpired, session]\n )\n\n const contextValue: ChatContextValue = {\n env,\n token,\n onTokenExpired,\n theme,\n client,\n }\n\n return <ChatContext.Provider value={contextValue}>{children}</ChatContext.Provider>\n}\n\nexport interface CreateChatThemeProps {\n theme?: DeepPartial<DefaultTheme>\n colorScheme?: ColorSchemeName\n}\n\nexport const useCreateChatTheme = ({\n theme: customTheme = {},\n colorScheme: appColorScheme,\n}: CreateChatThemeProps): ChatTheme => {\n const internalColorScheme = useColorScheme() || 'light'\n const colorScheme = appColorScheme || internalColorScheme\n\n const theme = {\n ...merge({}, defaultTheme(colorScheme), customTheme),\n colors: {\n ...merge({}, defaultTheme(colorScheme).colors, customTheme?.colors),\n },\n }\n\n return theme\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenLayout.d.ts","sourceRoot":"","sources":["../../src/navigation/screenLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"screenLayout.d.ts","sourceRoot":"","sources":["../../src/navigation/screenLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAA;CAAE,qBAY1E"}
|
|
@@ -3,11 +3,14 @@ import { QueryErrorResetBoundary } from '@tanstack/react-query';
|
|
|
3
3
|
import ErrorBoundary from '../components/error_boundary';
|
|
4
4
|
import { Suspense } from 'react';
|
|
5
5
|
import { Text } from '../components/display';
|
|
6
|
+
import { ApiProvider } from '../contexts';
|
|
6
7
|
export function ScreenLayout({ children }) {
|
|
7
|
-
return (<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
return (<ApiProvider>
|
|
9
|
+
<QueryErrorResetBoundary>
|
|
10
|
+
{({ reset }) => (<ErrorBoundary onReset={reset}>
|
|
11
|
+
<Suspense fallback={<Text>loading...</Text>}>{children}</Suspense>
|
|
12
|
+
</ErrorBoundary>)}
|
|
13
|
+
</QueryErrorResetBoundary>
|
|
14
|
+
</ApiProvider>);
|
|
12
15
|
}
|
|
13
16
|
//# sourceMappingURL=screenLayout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenLayout.js","sourceRoot":"","sources":["../../src/navigation/screenLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,aAAa,MAAM,8BAA8B,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"screenLayout.js","sourceRoot":"","sources":["../../src/navigation/screenLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,aAAa,MAAM,8BAA8B,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,UAAU,YAAY,CAAC,EAAE,QAAQ,EAAoC;IACzE,OAAO,CACL,CAAC,WAAW,CACV;MAAA,CAAC,uBAAuB,CACtB;QAAA,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CACd,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAC5B;YAAA,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,CACnE;UAAA,EAAE,aAAa,CAAC,CACjB,CACH;MAAA,EAAE,uBAAuB,CAC3B;IAAA,EAAE,WAAW,CAAC,CACf,CAAA;AACH,CAAC","sourcesContent":["import React from 'react'\nimport { QueryErrorResetBoundary } from '@tanstack/react-query'\nimport ErrorBoundary from '../components/error_boundary'\nimport { Suspense } from 'react'\nimport { Text } from '../components/display'\nimport { ApiProvider } from '../contexts'\n\nexport function ScreenLayout({ children }: { children: React.ReactElement }) {\n return (\n <ApiProvider>\n <QueryErrorResetBoundary>\n {({ reset }) => (\n <ErrorBoundary onReset={reset}>\n <Suspense fallback={<Text>loading...</Text>}>{children}</Suspense>\n </ErrorBoundary>\n )}\n </QueryErrorResetBoundary>\n </ApiProvider>\n )\n}\n"]}
|
package/build/utils/theme.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface DefaultTheme {
|
|
|
23
23
|
text: TextStyle;
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
-
export declare const defaultTheme: (colorScheme: ColorSchemeName) =>
|
|
26
|
+
export declare const defaultTheme: (colorScheme: ColorSchemeName) => ChatTheme;
|
|
27
27
|
export type TemporaryDefaultColorsType = Partial<ChatColors>;
|
|
28
28
|
interface ChatColors {
|
|
29
29
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAA;AAE/E,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,GAC5B,CAAC,OAAO,mBAAmB,CAAC,KAAK,GAAG,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;CACvE;AAED;;;;;;;;;;;;gDAYgD;AAEhD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAA;IAClB,qBAAqB,EAAE;QACrB,SAAS,EAAE,SAAS,CAAA;QACpB,IAAI,EAAE,SAAS,CAAA;KAChB,CAAA;CACF;AAED,eAAO,MAAM,YAAY,gBAAiB,eAAe,KAAG,
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAA;AAE/E,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,GAC5B,CAAC,OAAO,mBAAmB,CAAC,KAAK,GAAG,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;CACvE;AAED;;;;;;;;;;;;gDAYgD;AAEhD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAA;IAClB,qBAAqB,EAAE;QACrB,SAAS,EAAE,SAAS,CAAA;QACpB,IAAI,EAAE,SAAS,CAAA;KAChB,CAAA;CACF;AAED,eAAO,MAAM,YAAY,gBAAiB,eAAe,KAAG,SAqB3D,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;AAE5D,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;CAClB"}
|
package/build/utils/theme.js
CHANGED
|
@@ -2,8 +2,12 @@ import { tokens } from '../vendor/tapestry/tokens';
|
|
|
2
2
|
import { aliasTokensColorMap } from '../vendor/tapestry/alias_tokens_color_map';
|
|
3
3
|
export const defaultTheme = (colorScheme) => {
|
|
4
4
|
const scheme = colorScheme || 'light';
|
|
5
|
+
const defaultColors = {
|
|
6
|
+
...chatThemeColorMap[scheme],
|
|
7
|
+
...aliasTokensColorMap[scheme],
|
|
8
|
+
};
|
|
5
9
|
return {
|
|
6
|
-
colors:
|
|
10
|
+
colors: defaultColors,
|
|
7
11
|
temporaryProductBadge: {
|
|
8
12
|
container: {
|
|
9
13
|
paddingHorizontal: tokens.spacing1,
|
package/build/utils/theme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAA;AA6B/E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,WAA4B,
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAA;AA6B/E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,WAA4B,EAAa,EAAE;IACtE,MAAM,MAAM,GAAG,WAAW,IAAI,OAAO,CAAA;IAErC,MAAM,aAAa,GAAG;QACpB,GAAG,iBAAiB,CAAC,MAAM,CAAC;QAC5B,GAAG,mBAAmB,CAAC,MAAM,CAAC;KAC/B,CAAA;IAED,OAAO;QACL,MAAM,EAAE,aAAa;QACrB,qBAAqB,EAAE;YACrB,SAAS,EAAE;gBACT,iBAAiB,EAAE,MAAM,CAAC,QAAQ;gBAClC,eAAe,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC,mBAAmB;gBAChE,WAAW,EAAE,MAAM,CAAC,iBAAiB;aACtC;YACD,IAAI,EAAE;gBACJ,SAAS,EAAE,QAAQ;aACpB;SACF;KACF,CAAA;AACH,CAAC,CAAA;AAYD,MAAM,eAAe,GAAe;IAClC,IAAI,EAAE,OAAO;IACb,WAAW,EAAE,SAAS;IACtB,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,MAAM,CAAC,2BAA2B;IAC/C,SAAS,EAAE,KAAK;CACjB,CAAA;AAED,MAAM,cAAc,GAAe;IACjC,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,SAAS;IACtB,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,MAAM,CAAC,+BAA+B;IACnD,SAAS,EAAE,MAAM;CAClB,CAAA;AAED,MAAM,iBAAiB,GAAG;IACxB,KAAK,EAAE,eAAe;IACtB,IAAI,EAAE,cAAc;CACrB,CAAA","sourcesContent":["import { TextStyle, ViewStyle, ColorSchemeName } from 'react-native'\nimport { tokens } from '../vendor/tapestry/tokens'\nimport { aliasTokensColorMap } from '../vendor/tapestry/alias_tokens_color_map'\n\nexport interface ChatTheme extends DefaultTheme {\n colors: DefaultTheme['colors'] &\n (typeof aliasTokensColorMap.light | typeof aliasTokensColorMap.dark)\n}\n\n/** =============================================\n NOTE: The specific values for `colors` and the `productBadge` are temporary examples that can be replaced once we start building out UI. This line's comment can be removed at that time too.\n\n The default theme is intended to support two types of customizations:\n 1. Specific color properties for a chat component (eg. `primaryButtonBackgroundColor`)\n 2. Any styles for a specific component. (Use only one level of nesting.)\n ```\n primaryButton: {\n container: ViewStyle\n text: TextStyle\n }\n ```\n============================================= */\n\nexport interface DefaultTheme {\n colors: ChatColors\n temporaryProductBadge: {\n container: ViewStyle\n text: TextStyle\n }\n}\n\nexport const defaultTheme = (colorScheme: ColorSchemeName): ChatTheme => {\n const scheme = colorScheme || 'light'\n\n const defaultColors = {\n ...chatThemeColorMap[scheme],\n ...aliasTokensColorMap[scheme],\n }\n\n return {\n colors: defaultColors,\n temporaryProductBadge: {\n container: {\n paddingHorizontal: tokens.spacing1,\n backgroundColor: aliasTokensColorMap[scheme].fillColorNeutral070,\n borderWidth: tokens.borderSizeDefault,\n },\n text: {\n textAlign: 'center',\n },\n },\n }\n}\n\nexport type TemporaryDefaultColorsType = Partial<ChatColors>\n\ninterface ChatColors {\n name: string\n buttonStart: string | undefined\n buttonEnd: string | undefined\n interaction: string\n testColor: string\n}\n\nconst colorsChatLight: ChatColors = {\n name: 'light',\n buttonStart: undefined,\n buttonEnd: undefined,\n interaction: tokens.fillColorInteractionDefault,\n testColor: 'red',\n}\n\nconst colorsChatDark: ChatColors = {\n name: 'dark',\n buttonStart: undefined,\n buttonEnd: undefined,\n interaction: tokens.fillColorInteractionDefaultDark,\n testColor: 'blue',\n}\n\nconst chatThemeColorMap = {\n light: colorsChatLight,\n dark: colorsChatDark,\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "1.6.0",
|
|
3
|
+
"version": "1.6.1-qa-27.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"prettier": "^3.4.2",
|
|
47
47
|
"typescript": "<5.6.0"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "a9aa095bb68dc974460d9dad35fff2bd3770954a"
|
|
50
50
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { renderHook } from '@testing-library/react-native'
|
|
2
2
|
import { useTheme } from '../../hooks'
|
|
3
|
-
import { ChatProvider } from '../../contexts'
|
|
3
|
+
import { ChatProvider, CreateChatThemeProps } from '../../contexts'
|
|
4
4
|
import React from 'react'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
let themeProps: CreateChatThemeProps = {
|
|
7
|
+
theme: {
|
|
8
|
+
colors: {},
|
|
9
9
|
},
|
|
10
|
+
colorScheme: 'light',
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
const Wrapper = ({ children }: { children: React.ReactNode }) => {
|
|
@@ -22,7 +23,7 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => {
|
|
|
22
23
|
token_type: '',
|
|
23
24
|
},
|
|
24
25
|
onTokenExpired: () => null,
|
|
25
|
-
theme,
|
|
26
|
+
theme: themeProps,
|
|
26
27
|
}}
|
|
27
28
|
>
|
|
28
29
|
{children}
|
|
@@ -31,7 +32,40 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
test('should use theme', () => {
|
|
35
|
+
themeProps = {}
|
|
34
36
|
const { result } = renderHook(() => useTheme(), { wrapper: Wrapper })
|
|
35
37
|
|
|
36
38
|
expect(result.current).toBeDefined()
|
|
37
39
|
})
|
|
40
|
+
|
|
41
|
+
describe('configurable theme', () => {
|
|
42
|
+
test('should not error is theme is undefined', () => {
|
|
43
|
+
//@ts-expect-error
|
|
44
|
+
themeProps = undefined
|
|
45
|
+
const { result } = renderHook(() => useTheme(), { wrapper: Wrapper })
|
|
46
|
+
|
|
47
|
+
expect(result.current).toBeDefined()
|
|
48
|
+
expect(result.current.colors.testColor).toBe('red')
|
|
49
|
+
expect(result.current.colors.interaction).toBeDefined()
|
|
50
|
+
expect(result.current.colors.buttonStart).toBeUndefined()
|
|
51
|
+
expect(result.current.colors.buttonEnd).toBeUndefined()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('should deliver custom stuffs', () => {
|
|
55
|
+
themeProps = {
|
|
56
|
+
theme: {
|
|
57
|
+
colors: {
|
|
58
|
+
testColor: 'fuscia',
|
|
59
|
+
buttonStart: 'blue',
|
|
60
|
+
buttonEnd: 'red',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
colorScheme: 'dark',
|
|
64
|
+
}
|
|
65
|
+
const { result } = renderHook(() => useTheme(), { wrapper: Wrapper })
|
|
66
|
+
|
|
67
|
+
expect(result.current.colors.testColor).toBe('fuscia')
|
|
68
|
+
expect(result.current.colors.buttonStart).toBe('blue')
|
|
69
|
+
expect(result.current.colors.buttonEnd).toBe('red')
|
|
70
|
+
})
|
|
71
|
+
})
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { QueryClient, QueryClientProvider, QueryKey } from '@tanstack/react-query'
|
|
2
|
-
import React, { useEffect } from 'react'
|
|
2
|
+
import React, { useContext, useEffect, useRef } from 'react'
|
|
3
3
|
import { ViewProps } from 'react-native'
|
|
4
4
|
import { Client } from '../utils'
|
|
5
5
|
import { GetRequest } from '../utils/client/types'
|
|
6
|
+
import { ChatContext, ChatContextValue } from './chat_context'
|
|
6
7
|
|
|
7
8
|
let apiClient: Client | undefined
|
|
8
9
|
|
|
@@ -25,21 +26,34 @@ export const queryClient = new QueryClient({
|
|
|
25
26
|
},
|
|
26
27
|
})
|
|
27
28
|
|
|
28
|
-
export function ApiProvider({
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
apiClient = client
|
|
35
|
-
}, [client])
|
|
29
|
+
export function ApiProvider({ children }: ViewProps) {
|
|
30
|
+
const { token, env, client } = useContext(ChatContext)
|
|
31
|
+
const sessionChanged = useSessionChanged({ token, env })
|
|
32
|
+
|
|
33
|
+
apiClient = client
|
|
36
34
|
|
|
37
|
-
// TODO: CREATE CALLBACK TO INVALIDATE QUERIES
|
|
38
35
|
useEffect(() => {
|
|
39
36
|
if (!sessionChanged) return
|
|
40
37
|
|
|
41
|
-
queryClient.
|
|
38
|
+
queryClient.clear()
|
|
42
39
|
}, [sessionChanged])
|
|
43
40
|
|
|
44
41
|
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
45
42
|
}
|
|
43
|
+
|
|
44
|
+
function useSessionChanged(value: Pick<ChatContextValue, 'token' | 'env'>): boolean {
|
|
45
|
+
const { token: newToken, env: newEnv } = value
|
|
46
|
+
const { token: prevToken, env: prevEnv } = usePrevious<typeof value>(value)
|
|
47
|
+
|
|
48
|
+
return Boolean(prevToken && newToken !== prevToken) || Boolean(prevEnv && newEnv !== prevEnv)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function usePrevious<T>(value) {
|
|
52
|
+
const ref = useRef<T>(value)
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
ref.current = value
|
|
56
|
+
}, [value])
|
|
57
|
+
|
|
58
|
+
return ref.current
|
|
59
|
+
}
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { merge } from 'lodash'
|
|
2
|
-
import React, { createContext,
|
|
2
|
+
import React, { createContext, useMemo } from 'react'
|
|
3
3
|
import { ColorSchemeName, useColorScheme } from 'react-native'
|
|
4
4
|
import { DeepPartial, OAuthToken } from '../types'
|
|
5
|
-
import { defaultTheme, DefaultTheme } from '../utils/theme'
|
|
6
|
-
import { aliasTokensColorMap } from '../vendor/tapestry/alias_tokens_color_map'
|
|
7
|
-
import { ApiProvider } from './api_provider'
|
|
8
5
|
import { Client, ENV, Session } from '../utils'
|
|
6
|
+
import { ChatTheme, defaultTheme, DefaultTheme } from '../utils/theme'
|
|
9
7
|
|
|
10
|
-
type ChatContextValue = {
|
|
8
|
+
export type ChatContextValue = {
|
|
11
9
|
token?: OAuthToken
|
|
12
10
|
onTokenExpired: () => void
|
|
13
|
-
theme:
|
|
11
|
+
theme: ChatTheme
|
|
14
12
|
env?: ENV
|
|
15
13
|
client: Client
|
|
16
14
|
}
|
|
17
15
|
|
|
16
|
+
export interface ChatProviderProps extends Omit<ChatContextValue, 'client' | 'theme'> {
|
|
17
|
+
theme: CreateChatThemeProps
|
|
18
|
+
}
|
|
19
|
+
|
|
18
20
|
const defaultChatClient = new Client({
|
|
19
21
|
app: 'chat',
|
|
20
22
|
session: new Session(),
|
|
@@ -23,22 +25,16 @@ const defaultChatClient = new Client({
|
|
|
23
25
|
})
|
|
24
26
|
|
|
25
27
|
export const ChatContext = createContext<ChatContextValue>({
|
|
26
|
-
theme:
|
|
28
|
+
theme: defaultTheme('light'),
|
|
27
29
|
token: undefined,
|
|
28
30
|
env: undefined,
|
|
29
31
|
onTokenExpired: () => {},
|
|
30
32
|
client: defaultChatClient,
|
|
31
33
|
})
|
|
32
34
|
|
|
33
|
-
export function ChatProvider({
|
|
34
|
-
children,
|
|
35
|
-
value,
|
|
36
|
-
}: {
|
|
37
|
-
children: any
|
|
38
|
-
value: Omit<ChatContextValue, 'client'>
|
|
39
|
-
}) {
|
|
35
|
+
export function ChatProvider({ children, value }: { children: any; value: ChatProviderProps }) {
|
|
40
36
|
const { env, token, onTokenExpired } = value
|
|
41
|
-
const theme = useCreateChatTheme(value.theme)
|
|
37
|
+
const theme = useCreateChatTheme(value.theme || {})
|
|
42
38
|
const session = useMemo(() => new Session({ token, env }), [env, token])
|
|
43
39
|
const client = useMemo(
|
|
44
40
|
() =>
|
|
@@ -50,7 +46,6 @@ export function ChatProvider({
|
|
|
50
46
|
}),
|
|
51
47
|
[onTokenExpired, session]
|
|
52
48
|
)
|
|
53
|
-
const sessionChanged = useSessionChanged({ token, env })
|
|
54
49
|
|
|
55
50
|
const contextValue: ChatContextValue = {
|
|
56
51
|
env,
|
|
@@ -60,35 +55,10 @@ export function ChatProvider({
|
|
|
60
55
|
client,
|
|
61
56
|
}
|
|
62
57
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<ChatContext.Provider value={contextValue}>
|
|
67
|
-
<ApiProvider sessionChanged={sessionChanged} client={client}>
|
|
68
|
-
{children}
|
|
69
|
-
</ApiProvider>
|
|
70
|
-
</ChatContext.Provider>
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function useSessionChanged(value: Pick<ChatContextValue, 'token' | 'env'>): boolean {
|
|
75
|
-
const { token: newToken, env: newEnv } = value
|
|
76
|
-
const { token: prevToken, env: prevEnv } = usePrevious<typeof value>(value)
|
|
77
|
-
|
|
78
|
-
return Boolean(prevToken && newToken !== prevToken) || Boolean(prevEnv && newEnv !== prevEnv)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function usePrevious<T>(value) {
|
|
82
|
-
const ref = useRef<T>(value)
|
|
83
|
-
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
ref.current = value
|
|
86
|
-
}, [value])
|
|
87
|
-
|
|
88
|
-
return ref.current
|
|
58
|
+
return <ChatContext.Provider value={contextValue}>{children}</ChatContext.Provider>
|
|
89
59
|
}
|
|
90
60
|
|
|
91
|
-
interface CreateChatThemeProps {
|
|
61
|
+
export interface CreateChatThemeProps {
|
|
92
62
|
theme?: DeepPartial<DefaultTheme>
|
|
93
63
|
colorScheme?: ColorSchemeName
|
|
94
64
|
}
|
|
@@ -96,19 +66,16 @@ interface CreateChatThemeProps {
|
|
|
96
66
|
export const useCreateChatTheme = ({
|
|
97
67
|
theme: customTheme = {},
|
|
98
68
|
colorScheme: appColorScheme,
|
|
99
|
-
}: CreateChatThemeProps) => {
|
|
69
|
+
}: CreateChatThemeProps): ChatTheme => {
|
|
100
70
|
const internalColorScheme = useColorScheme() || 'light'
|
|
101
71
|
const colorScheme = appColorScheme || internalColorScheme
|
|
102
72
|
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
colors
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
},
|
|
110
|
-
}
|
|
111
|
-
}, [colorScheme, customTheme])
|
|
73
|
+
const theme = {
|
|
74
|
+
...merge({}, defaultTheme(colorScheme), customTheme),
|
|
75
|
+
colors: {
|
|
76
|
+
...merge({}, defaultTheme(colorScheme).colors, customTheme?.colors),
|
|
77
|
+
},
|
|
78
|
+
}
|
|
112
79
|
|
|
113
|
-
return
|
|
80
|
+
return theme
|
|
114
81
|
}
|
|
@@ -3,15 +3,18 @@ import { QueryErrorResetBoundary } from '@tanstack/react-query'
|
|
|
3
3
|
import ErrorBoundary from '../components/error_boundary'
|
|
4
4
|
import { Suspense } from 'react'
|
|
5
5
|
import { Text } from '../components/display'
|
|
6
|
+
import { ApiProvider } from '../contexts'
|
|
6
7
|
|
|
7
8
|
export function ScreenLayout({ children }: { children: React.ReactElement }) {
|
|
8
9
|
return (
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
<ApiProvider>
|
|
11
|
+
<QueryErrorResetBoundary>
|
|
12
|
+
{({ reset }) => (
|
|
13
|
+
<ErrorBoundary onReset={reset}>
|
|
14
|
+
<Suspense fallback={<Text>loading...</Text>}>{children}</Suspense>
|
|
15
|
+
</ErrorBoundary>
|
|
16
|
+
)}
|
|
17
|
+
</QueryErrorResetBoundary>
|
|
18
|
+
</ApiProvider>
|
|
16
19
|
)
|
|
17
20
|
}
|
package/src/utils/theme.ts
CHANGED
|
@@ -29,11 +29,16 @@ export interface DefaultTheme {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export const defaultTheme = (colorScheme: ColorSchemeName):
|
|
32
|
+
export const defaultTheme = (colorScheme: ColorSchemeName): ChatTheme => {
|
|
33
33
|
const scheme = colorScheme || 'light'
|
|
34
34
|
|
|
35
|
+
const defaultColors = {
|
|
36
|
+
...chatThemeColorMap[scheme],
|
|
37
|
+
...aliasTokensColorMap[scheme],
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
return {
|
|
36
|
-
colors:
|
|
41
|
+
colors: defaultColors,
|
|
37
42
|
temporaryProductBadge: {
|
|
38
43
|
container: {
|
|
39
44
|
paddingHorizontal: tokens.spacing1,
|