@planningcenter/chat-react-native 2.1.0-rc.0 → 2.1.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/index.d.ts +1 -1
- package/build/components/index.d.ts.map +1 -1
- package/build/components/index.js +1 -1
- package/build/components/index.js.map +1 -1
- package/build/components/{error_boundary.d.ts → page/error_boundary.d.ts} +6 -4
- package/build/components/page/error_boundary.d.ts.map +1 -0
- package/build/components/page/error_boundary.js +115 -0
- package/build/components/page/error_boundary.js.map +1 -0
- package/build/components/page/loading.d.ts +3 -0
- package/build/components/page/loading.d.ts.map +1 -0
- package/build/components/page/loading.js +24 -0
- package/build/components/page/loading.js.map +1 -0
- package/build/navigation/index.d.ts +6 -2
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +7 -4
- package/build/navigation/index.js.map +1 -1
- package/build/navigation/screenLayout.d.ts.map +1 -1
- package/build/navigation/screenLayout.js +5 -8
- package/build/navigation/screenLayout.js.map +1 -1
- package/package.json +2 -2
- package/src/components/index.tsx +1 -1
- package/src/components/page/error_boundary.tsx +135 -0
- package/src/components/page/loading.tsx +28 -0
- package/src/navigation/index.tsx +13 -5
- package/src/navigation/screenLayout.tsx +5 -10
- package/build/components/error_boundary.d.ts.map +0 -1
- package/build/components/error_boundary.js +0 -24
- package/build/components/error_boundary.js.map +0 -1
- package/src/components/error_boundary.tsx +0 -27
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.tsx"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.tsx"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,uBAAuB,CAAA;AACrC,cAAc,WAAW,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.tsx"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.tsx"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,uBAAuB,CAAA;AACrC,cAAc,WAAW,CAAA","sourcesContent":["export * from './conversations'\nexport * from './page/error_boundary'\nexport * from './display'\n"]}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from 'react';
|
|
2
|
+
type ErrorBoundaryState = {
|
|
3
|
+
error: Response | Error | null;
|
|
4
|
+
unsubscriber: () => void;
|
|
5
|
+
};
|
|
2
6
|
declare class ErrorBoundary extends React.Component<PropsWithChildren<{
|
|
3
7
|
onReset?: () => void;
|
|
4
8
|
}>> {
|
|
5
|
-
state:
|
|
6
|
-
error: null;
|
|
7
|
-
unsubscriber: () => void;
|
|
8
|
-
};
|
|
9
|
+
state: ErrorBoundaryState;
|
|
9
10
|
componentDidCatch(error: any): void;
|
|
10
11
|
handleError(error: any): void;
|
|
12
|
+
handleReset: () => void;
|
|
11
13
|
render(): string | number | boolean | React.JSX.Element | Iterable<React.ReactNode> | null | undefined;
|
|
12
14
|
}
|
|
13
15
|
export default ErrorBoundary;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error_boundary.d.ts","sourceRoot":"","sources":["../../../src/components/page/error_boundary.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,iBAAiB,EAAsB,MAAM,OAAO,CAAA;AAMpE,KAAK,kBAAkB,GAAG;IACxB,KAAK,EAAE,QAAQ,GAAG,KAAK,GAAG,IAAI,CAAA;IAC9B,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAAA;AAED,cAAM,aAAc,SAAQ,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC;IAAE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC,CAAC;IACtF,KAAK,EAAE,kBAAkB,CAGxB;IAED,iBAAiB,CAAC,KAAK,EAAE,GAAG;IAI5B,WAAW,CAAC,KAAK,EAAE,GAAG;IAItB,WAAW,aAGV;IAED,MAAM;CAOP;AA+FD,eAAe,aAAa,CAAA"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { useNavigation } from '@react-navigation/native';
|
|
2
|
+
import { useQueryErrorResetBoundary } from '@tanstack/react-query';
|
|
3
|
+
import React, { useEffect, useMemo } from 'react';
|
|
4
|
+
import { StyleSheet, View } from 'react-native';
|
|
5
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
6
|
+
import { Button, Heading, Icon, Text } from '../display';
|
|
7
|
+
import { useTheme } from '../../hooks';
|
|
8
|
+
class ErrorBoundary extends React.Component {
|
|
9
|
+
state = {
|
|
10
|
+
error: null,
|
|
11
|
+
unsubscriber: () => { },
|
|
12
|
+
};
|
|
13
|
+
componentDidCatch(error) {
|
|
14
|
+
this.handleError(error);
|
|
15
|
+
}
|
|
16
|
+
handleError(error) {
|
|
17
|
+
this.setState({ error });
|
|
18
|
+
}
|
|
19
|
+
handleReset = () => {
|
|
20
|
+
this.props.onReset?.();
|
|
21
|
+
this.setState({ error: null });
|
|
22
|
+
};
|
|
23
|
+
render() {
|
|
24
|
+
if (this.state.error) {
|
|
25
|
+
return <ErrorView error={this.state.error} onReset={this.handleReset}/>;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return this.props.children;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function ErrorView({ error, onReset }) {
|
|
33
|
+
const { reset } = useQueryErrorResetBoundary();
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!reset)
|
|
36
|
+
return;
|
|
37
|
+
return () => {
|
|
38
|
+
onReset();
|
|
39
|
+
reset();
|
|
40
|
+
};
|
|
41
|
+
}, [reset, onReset]);
|
|
42
|
+
if (error instanceof Response) {
|
|
43
|
+
return <ResponseErrorView error={error} onReset={onReset}/>;
|
|
44
|
+
}
|
|
45
|
+
return <ErrorContent heading={'Oops!'} body={'Something unexpected happened.'}/>;
|
|
46
|
+
}
|
|
47
|
+
function ResponseErrorView({ error: response }) {
|
|
48
|
+
const { status } = response;
|
|
49
|
+
const heading = useMemo(() => {
|
|
50
|
+
switch (status) {
|
|
51
|
+
case 403:
|
|
52
|
+
return 'Permission required';
|
|
53
|
+
case 404:
|
|
54
|
+
return 'Content not found';
|
|
55
|
+
default:
|
|
56
|
+
return 'Oops!';
|
|
57
|
+
}
|
|
58
|
+
}, [status]);
|
|
59
|
+
const body = useMemo(() => {
|
|
60
|
+
switch (status) {
|
|
61
|
+
case 403:
|
|
62
|
+
return 'Contact your administrator for access.';
|
|
63
|
+
case 404:
|
|
64
|
+
return 'If you believe something should be here, please reach out to your administrator.';
|
|
65
|
+
default:
|
|
66
|
+
return 'Something unexpected happened.';
|
|
67
|
+
}
|
|
68
|
+
}, [status]);
|
|
69
|
+
return <ErrorContent heading={heading} body={body}/>;
|
|
70
|
+
}
|
|
71
|
+
function ErrorContent({ heading, body }) {
|
|
72
|
+
const styles = useStyles();
|
|
73
|
+
const navigation = useNavigation();
|
|
74
|
+
return (<View style={styles.container}>
|
|
75
|
+
<Icon name="general.outlinedTextMessage" size={32} color={styles.icon.color}/>
|
|
76
|
+
<View style={styles.information}>
|
|
77
|
+
<Heading variant="h3" style={styles.heading}>
|
|
78
|
+
{heading}
|
|
79
|
+
</Heading>
|
|
80
|
+
<Text style={styles.body}>{body}</Text>
|
|
81
|
+
</View>
|
|
82
|
+
<Button variant="outline" onPress={navigation.goBack} title="Go back" size="md"/>
|
|
83
|
+
</View>);
|
|
84
|
+
}
|
|
85
|
+
const useStyles = () => {
|
|
86
|
+
const theme = useTheme();
|
|
87
|
+
const { bottom } = useSafeAreaInsets();
|
|
88
|
+
return StyleSheet.create({
|
|
89
|
+
container: {
|
|
90
|
+
flex: 1,
|
|
91
|
+
justifyContent: 'center',
|
|
92
|
+
alignItems: 'center',
|
|
93
|
+
gap: 24,
|
|
94
|
+
paddingHorizontal: 16,
|
|
95
|
+
paddingBottom: bottom,
|
|
96
|
+
},
|
|
97
|
+
information: {
|
|
98
|
+
alignItems: 'center',
|
|
99
|
+
gap: 8,
|
|
100
|
+
},
|
|
101
|
+
heading: {
|
|
102
|
+
textAlign: 'center',
|
|
103
|
+
lineHeight: 20,
|
|
104
|
+
},
|
|
105
|
+
body: {
|
|
106
|
+
textAlign: 'center',
|
|
107
|
+
lineHeight: 20,
|
|
108
|
+
},
|
|
109
|
+
icon: {
|
|
110
|
+
color: theme.colors.iconColorDefaultDisabled,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
export default ErrorBoundary;
|
|
115
|
+
//# sourceMappingURL=error_boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error_boundary.js","sourceRoot":"","sources":["../../../src/components/page/error_boundary.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport { useQueryErrorResetBoundary } from '@tanstack/react-query'\nimport React, { PropsWithChildren, useEffect, useMemo } from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { Button, Heading, Icon, Text } from '../display'\nimport { useTheme } from '../../hooks'\n\ntype ErrorBoundaryState = {\n error: Response | Error | null\n unsubscriber: () => void\n}\n\nclass ErrorBoundary extends React.Component<PropsWithChildren<{ onReset?: () => void }>> {\n state: ErrorBoundaryState = {\n error: null,\n unsubscriber: () => {},\n }\n\n componentDidCatch(error: any) {\n this.handleError(error)\n }\n\n handleError(error: any) {\n this.setState({ error })\n }\n\n handleReset = () => {\n this.props.onReset?.()\n this.setState({ error: null })\n }\n\n render() {\n if (this.state.error) {\n return <ErrorView error={this.state.error} onReset={this.handleReset} />\n } else {\n return this.props.children\n }\n }\n}\n\nfunction ErrorView({ error, onReset }: { error: Error | Response; onReset: () => void }) {\n const { reset } = useQueryErrorResetBoundary()\n useEffect(() => {\n if (!reset) return\n\n return () => {\n onReset()\n reset()\n }\n }, [reset, onReset])\n\n if (error instanceof Response) {\n return <ResponseErrorView error={error} onReset={onReset} />\n }\n\n return <ErrorContent heading={'Oops!'} body={'Something unexpected happened.'} />\n}\n\nfunction ResponseErrorView({ error: response }: { error: Response; onReset: () => void }) {\n const { status } = response\n const heading = useMemo(() => {\n switch (status) {\n case 403:\n return 'Permission required'\n case 404:\n return 'Content not found'\n default:\n return 'Oops!'\n }\n }, [status])\n\n const body = useMemo(() => {\n switch (status) {\n case 403:\n return 'Contact your administrator for access.'\n case 404:\n return 'If you believe something should be here, please reach out to your administrator.'\n default:\n return 'Something unexpected happened.'\n }\n }, [status])\n\n return <ErrorContent heading={heading} body={body} />\n}\n\nfunction ErrorContent({ heading, body }: { heading: string; body: string }) {\n const styles = useStyles()\n const navigation = useNavigation()\n\n return (\n <View style={styles.container}>\n <Icon name=\"general.outlinedTextMessage\" size={32} color={styles.icon.color} />\n <View style={styles.information}>\n <Heading variant=\"h3\" style={styles.heading}>\n {heading}\n </Heading>\n <Text style={styles.body}>{body}</Text>\n </View>\n <Button variant=\"outline\" onPress={navigation.goBack} title=\"Go back\" size=\"md\" />\n </View>\n )\n}\n\nconst useStyles = () => {\n const theme = useTheme()\n const { bottom } = useSafeAreaInsets()\n return StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n gap: 24,\n paddingHorizontal: 16,\n paddingBottom: bottom,\n },\n information: {\n alignItems: 'center',\n gap: 8,\n },\n heading: {\n textAlign: 'center',\n lineHeight: 20,\n },\n body: {\n textAlign: 'center',\n lineHeight: 20,\n },\n icon: {\n color: theme.colors.iconColorDefaultDisabled,\n },\n })\n}\n\nexport default ErrorBoundary\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loading.d.ts","sourceRoot":"","sources":["../../../src/components/page/loading.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,wBAAgB,cAAc,sBAQ7B"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useTheme } from '@react-navigation/native';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { StyleSheet, View } from 'react-native';
|
|
4
|
+
import { Spinner } from '../display';
|
|
5
|
+
export function DefaultLoading() {
|
|
6
|
+
const styles = useStyles();
|
|
7
|
+
return (<View style={styles.container}>
|
|
8
|
+
<Spinner size={48}/>
|
|
9
|
+
</View>);
|
|
10
|
+
}
|
|
11
|
+
const useStyles = () => {
|
|
12
|
+
const theme = useTheme();
|
|
13
|
+
return StyleSheet.create({
|
|
14
|
+
container: {
|
|
15
|
+
flex: 1,
|
|
16
|
+
justifyContent: 'center',
|
|
17
|
+
alignItems: 'center',
|
|
18
|
+
},
|
|
19
|
+
loading: {
|
|
20
|
+
color: theme.colors.text,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=loading.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loading.js","sourceRoot":"","sources":["../../../src/components/page/loading.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;MAAA,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EACpB;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;IACxB,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE;YACT,IAAI,EAAE,CAAC;YACP,cAAc,EAAE,QAAQ;YACxB,UAAU,EAAE,QAAQ;SACrB;QACD,OAAO,EAAE;YACP,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;SACzB;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { useTheme } from '@react-navigation/native'\nimport React from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { Spinner } from '../display'\n\nexport function DefaultLoading() {\n const styles = useStyles()\n\n return (\n <View style={styles.container}>\n <Spinner size={48} />\n </View>\n )\n}\n\nconst useStyles = () => {\n const theme = useTheme()\n return StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n },\n loading: {\n color: theme.colors.text,\n },\n })\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { StaticParamList } from '@react-navigation/native';
|
|
3
|
+
import { NativeStackHeaderLeftProps, NativeStackHeaderRightProps } from '@react-navigation/native-stack';
|
|
3
4
|
import { NotFound } from '../screens/not_found';
|
|
4
5
|
import { ScreenLayout } from './screenLayout';
|
|
5
6
|
import { ConversationsScreen } from '../screens/conversations_screen';
|
|
@@ -17,6 +18,9 @@ export declare const ChatStack: import("@react-navigation/native").TypedNavigato
|
|
|
17
18
|
};
|
|
18
19
|
Navigator: ({ id, initialRouteName, children, layout, screenListeners, screenOptions, screenLayout, UNSTABLE_getStateForRouteNamesChange, ...rest }: import("@react-navigation/native-stack").NativeStackNavigatorProps) => import("react/jsx-runtime").JSX.Element;
|
|
19
20
|
}, {
|
|
21
|
+
readonly screenOptions: {
|
|
22
|
+
readonly headerBackButtonDisplayMode: "minimal";
|
|
23
|
+
};
|
|
20
24
|
readonly screenLayout: typeof ScreenLayout;
|
|
21
25
|
readonly screens: {
|
|
22
26
|
readonly Conversations: {
|
|
@@ -27,8 +31,8 @@ export declare const ChatStack: import("@react-navigation/native").TypedNavigato
|
|
|
27
31
|
theme: ReactNavigation.Theme;
|
|
28
32
|
}) => {
|
|
29
33
|
headerTitle: string;
|
|
30
|
-
headerLeft: () => React.JSX.Element;
|
|
31
|
-
headerRight: () => React.JSX.Element;
|
|
34
|
+
headerLeft: ({ tintColor }: NativeStackHeaderLeftProps) => React.JSX.Element;
|
|
35
|
+
headerRight: (props: NativeStackHeaderRightProps) => React.JSX.Element;
|
|
32
36
|
};
|
|
33
37
|
};
|
|
34
38
|
readonly Conversation: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/navigation/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/navigation/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAEL,0BAA0B,EAC1B,2BAA2B,EAC5B,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAGnE,OAAO,EACL,oBAAoB,EAErB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EAAE,eAAe,EAA0B,MAAM,6BAA6B,CAAA;AAErF,eAAO,MAAM,SAAS;;;;;;;;;uOARmC,mBACzD;;;;;;;;;;;;uBA8DyugB,gBAAiB,KAAK;;;4CA7C3tgB,0BAA0B;qCAKjC,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;EA+BtD,CAAA;AAEF,KAAK,kBAAkB,GAAG,eAAe,CAAC,OAAO,SAAS,CAAC,CAAA;AAE3D,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,eAAe,CAAC;QACxB,UAAU,aAAc,SAAQ,kBAAkB;SAAG;KACtD;CACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
|
2
|
+
import { createNativeStackNavigator, } from '@react-navigation/native-stack';
|
|
3
3
|
import { NotFound } from '../screens/not_found';
|
|
4
4
|
import { ScreenLayout } from './screenLayout';
|
|
5
5
|
import { ConversationsScreen } from '../screens/conversations_screen';
|
|
@@ -9,16 +9,19 @@ import { Icon } from '../components';
|
|
|
9
9
|
import { MessageActionsScreen, MessageActionsScreenOptions, } from '../screens/message_actions_screen';
|
|
10
10
|
import { ReactionsScreen, ReactionsScreenOptions } from '../screens/reactions_screen';
|
|
11
11
|
export const ChatStack = createNativeStackNavigator({
|
|
12
|
+
screenOptions: {
|
|
13
|
+
headerBackButtonDisplayMode: 'minimal',
|
|
14
|
+
},
|
|
12
15
|
screenLayout: ScreenLayout,
|
|
13
16
|
screens: {
|
|
14
17
|
Conversations: {
|
|
15
18
|
screen: ConversationsScreen,
|
|
16
19
|
options: ({ route, navigation }) => ({
|
|
17
20
|
headerTitle: route.params?.title ?? 'Chat',
|
|
18
|
-
headerLeft: () => (<HeaderButton>
|
|
19
|
-
<Icon name="general.threeReducingHorizontalBars" size={18}/>
|
|
21
|
+
headerLeft: ({ tintColor }) => (<HeaderButton>
|
|
22
|
+
<Icon name="general.threeReducingHorizontalBars" size={18} color={tintColor}/>
|
|
20
23
|
</HeaderButton>),
|
|
21
|
-
headerRight: () => (<HeaderBackButton
|
|
24
|
+
headerRight: (props) => (<HeaderBackButton backImage={() => <Icon name="general.x" size={18} color={props.tintColor}/>} onPress={navigation.goBack} {...props}/>),
|
|
22
25
|
}),
|
|
23
26
|
},
|
|
24
27
|
Conversation: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/navigation/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/navigation/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EACL,0BAA0B,GAG3B,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC3E,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EACL,oBAAoB,EACpB,2BAA2B,GAC5B,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAErF,MAAM,CAAC,MAAM,SAAS,GAAG,0BAA0B,CAAC;IAClD,aAAa,EAAE;QACb,2BAA2B,EAAE,SAAS;KACvC;IACD,YAAY,EAAE,YAAY;IAC1B,OAAO,EAAE;QACP,aAAa,EAAE;YACb,MAAM,EAAE,mBAAmB;YAC3B,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;gBACnC,WAAW,EAAG,KAAK,CAAC,MAA6B,EAAE,KAAK,IAAI,MAAM;gBAClE,UAAU,EAAE,CAAC,EAAE,SAAS,EAA8B,EAAE,EAAE,CAAC,CACzD,CAAC,YAAY,CACX;YAAA,CAAC,IAAI,CAAC,IAAI,CAAC,qCAAqC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAC9E;UAAA,EAAE,YAAY,CAAC,CAChB;gBACD,WAAW,EAAE,CAAC,KAAkC,EAAE,EAAE,CAAC,CACnD,CAAC,gBAAgB,CACf,SAAS,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,EAAG,CAAC,CAC7E,OAAO,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAC3B,IAAI,KAAK,CAAC,EACV,CACH;aACF,CAAC;SACH;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,kBAAkB;SAC3B;QACD,cAAc,EAAE;YACd,MAAM,EAAE,oBAAoB;YAC5B,gEAAgE;YAChE,OAAO,EAAE,2BAA2B;SACrC;QACD,SAAS,EAAE;YACT,MAAM,EAAE,eAAe;YACvB,OAAO,EAAE,sBAAsB;SAChC;QACD,QAAQ,EAAE;YACR,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE;gBACP,KAAK,EAAE,KAAK;aACb;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,GAAG;aACV;SACF;KACF;CACF,CAAC,CAAA","sourcesContent":["import React from 'react'\nimport { StaticParamList } from '@react-navigation/native'\nimport {\n createNativeStackNavigator,\n NativeStackHeaderLeftProps,\n NativeStackHeaderRightProps,\n} from '@react-navigation/native-stack'\nimport { NotFound } from '../screens/not_found'\nimport { ScreenLayout } from './screenLayout'\nimport { ConversationsScreen } from '../screens/conversations_screen'\nimport { ConversationScreen } from '../screens/conversation_screen'\nimport { HeaderBackButton, HeaderButton } from '@react-navigation/elements'\nimport { Icon } from '../components'\nimport {\n MessageActionsScreen,\n MessageActionsScreenOptions,\n} from '../screens/message_actions_screen'\nimport { ReactionsScreen, ReactionsScreenOptions } from '../screens/reactions_screen'\n\nexport const ChatStack = createNativeStackNavigator({\n screenOptions: {\n headerBackButtonDisplayMode: 'minimal',\n },\n screenLayout: ScreenLayout,\n screens: {\n Conversations: {\n screen: ConversationsScreen,\n options: ({ route, navigation }) => ({\n headerTitle: (route.params as { title?: string })?.title ?? 'Chat',\n headerLeft: ({ tintColor }: NativeStackHeaderLeftProps) => (\n <HeaderButton>\n <Icon name=\"general.threeReducingHorizontalBars\" size={18} color={tintColor} />\n </HeaderButton>\n ),\n headerRight: (props: NativeStackHeaderRightProps) => (\n <HeaderBackButton\n backImage={() => <Icon name=\"general.x\" size={18} color={props.tintColor} />}\n onPress={navigation.goBack}\n {...props}\n />\n ),\n }),\n },\n Conversation: {\n screen: ConversationScreen,\n },\n MessageActions: {\n screen: MessageActionsScreen,\n // Something about sheetAllowedDetents declared inline breaks TS\n options: MessageActionsScreenOptions,\n },\n Reactions: {\n screen: ReactionsScreen,\n options: ReactionsScreenOptions,\n },\n NotFound: {\n screen: NotFound,\n options: {\n title: '404',\n },\n linking: {\n path: '*',\n },\n },\n },\n})\n\ntype ChatStackParamList = StaticParamList<typeof ChatStack>\n\ndeclare global {\n namespace ReactNavigation {\n interface RootParamList extends ChatStackParamList {}\n }\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;AAMzB,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAA;CAAE,qBAQ1E"}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
3
|
-
import ErrorBoundary from '../components/error_boundary';
|
|
2
|
+
import ErrorBoundary from '../components/page/error_boundary';
|
|
4
3
|
import { Suspense } from 'react';
|
|
5
|
-
import { Text } from '../components/display';
|
|
6
4
|
import { ApiProvider } from '../contexts';
|
|
5
|
+
import { DefaultLoading } from '../components/page/loading';
|
|
7
6
|
export function ScreenLayout({ children }) {
|
|
8
7
|
return (<ApiProvider>
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
</ErrorBoundary>)}
|
|
13
|
-
</QueryErrorResetBoundary>
|
|
8
|
+
<ErrorBoundary>
|
|
9
|
+
<Suspense fallback={<DefaultLoading />}>{children}</Suspense>
|
|
10
|
+
</ErrorBoundary>
|
|
14
11
|
</ApiProvider>);
|
|
15
12
|
}
|
|
16
13
|
//# 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,
|
|
1
|
+
{"version":3,"file":"screenLayout.js","sourceRoot":"","sources":["../../src/navigation/screenLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,aAAa,MAAM,mCAAmC,CAAA;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAE3D,MAAM,UAAU,YAAY,CAAC,EAAE,QAAQ,EAAoC;IACzE,OAAO,CACL,CAAC,WAAW,CACV;MAAA,CAAC,aAAa,CACZ;QAAA,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,AAAD,EAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAC9D;MAAA,EAAE,aAAa,CACjB;IAAA,EAAE,WAAW,CAAC,CACf,CAAA;AACH,CAAC","sourcesContent":["import React from 'react'\nimport ErrorBoundary from '../components/page/error_boundary'\nimport { Suspense } from 'react'\nimport { ApiProvider } from '../contexts'\nimport { DefaultLoading } from '../components/page/loading'\n\nexport function ScreenLayout({ children }: { children: React.ReactElement }) {\n return (\n <ApiProvider>\n <ErrorBoundary>\n <Suspense fallback={<DefaultLoading />}>{children}</Suspense>\n </ErrorBoundary>\n </ApiProvider>\n )\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "2.1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"prettier": "^3.4.2",
|
|
52
52
|
"typescript": "<5.6.0"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "7960721dcdf26174d4029bc7fe281a9429adde43"
|
|
55
55
|
}
|
package/src/components/index.tsx
CHANGED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { useNavigation } from '@react-navigation/native'
|
|
2
|
+
import { useQueryErrorResetBoundary } from '@tanstack/react-query'
|
|
3
|
+
import React, { PropsWithChildren, useEffect, useMemo } from 'react'
|
|
4
|
+
import { StyleSheet, View } from 'react-native'
|
|
5
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
6
|
+
import { Button, Heading, Icon, Text } from '../display'
|
|
7
|
+
import { useTheme } from '../../hooks'
|
|
8
|
+
|
|
9
|
+
type ErrorBoundaryState = {
|
|
10
|
+
error: Response | Error | null
|
|
11
|
+
unsubscriber: () => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class ErrorBoundary extends React.Component<PropsWithChildren<{ onReset?: () => void }>> {
|
|
15
|
+
state: ErrorBoundaryState = {
|
|
16
|
+
error: null,
|
|
17
|
+
unsubscriber: () => {},
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
componentDidCatch(error: any) {
|
|
21
|
+
this.handleError(error)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
handleError(error: any) {
|
|
25
|
+
this.setState({ error })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
handleReset = () => {
|
|
29
|
+
this.props.onReset?.()
|
|
30
|
+
this.setState({ error: null })
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
render() {
|
|
34
|
+
if (this.state.error) {
|
|
35
|
+
return <ErrorView error={this.state.error} onReset={this.handleReset} />
|
|
36
|
+
} else {
|
|
37
|
+
return this.props.children
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function ErrorView({ error, onReset }: { error: Error | Response; onReset: () => void }) {
|
|
43
|
+
const { reset } = useQueryErrorResetBoundary()
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!reset) return
|
|
46
|
+
|
|
47
|
+
return () => {
|
|
48
|
+
onReset()
|
|
49
|
+
reset()
|
|
50
|
+
}
|
|
51
|
+
}, [reset, onReset])
|
|
52
|
+
|
|
53
|
+
if (error instanceof Response) {
|
|
54
|
+
return <ResponseErrorView error={error} onReset={onReset} />
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return <ErrorContent heading={'Oops!'} body={'Something unexpected happened.'} />
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function ResponseErrorView({ error: response }: { error: Response; onReset: () => void }) {
|
|
61
|
+
const { status } = response
|
|
62
|
+
const heading = useMemo(() => {
|
|
63
|
+
switch (status) {
|
|
64
|
+
case 403:
|
|
65
|
+
return 'Permission required'
|
|
66
|
+
case 404:
|
|
67
|
+
return 'Content not found'
|
|
68
|
+
default:
|
|
69
|
+
return 'Oops!'
|
|
70
|
+
}
|
|
71
|
+
}, [status])
|
|
72
|
+
|
|
73
|
+
const body = useMemo(() => {
|
|
74
|
+
switch (status) {
|
|
75
|
+
case 403:
|
|
76
|
+
return 'Contact your administrator for access.'
|
|
77
|
+
case 404:
|
|
78
|
+
return 'If you believe something should be here, please reach out to your administrator.'
|
|
79
|
+
default:
|
|
80
|
+
return 'Something unexpected happened.'
|
|
81
|
+
}
|
|
82
|
+
}, [status])
|
|
83
|
+
|
|
84
|
+
return <ErrorContent heading={heading} body={body} />
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function ErrorContent({ heading, body }: { heading: string; body: string }) {
|
|
88
|
+
const styles = useStyles()
|
|
89
|
+
const navigation = useNavigation()
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<View style={styles.container}>
|
|
93
|
+
<Icon name="general.outlinedTextMessage" size={32} color={styles.icon.color} />
|
|
94
|
+
<View style={styles.information}>
|
|
95
|
+
<Heading variant="h3" style={styles.heading}>
|
|
96
|
+
{heading}
|
|
97
|
+
</Heading>
|
|
98
|
+
<Text style={styles.body}>{body}</Text>
|
|
99
|
+
</View>
|
|
100
|
+
<Button variant="outline" onPress={navigation.goBack} title="Go back" size="md" />
|
|
101
|
+
</View>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const useStyles = () => {
|
|
106
|
+
const theme = useTheme()
|
|
107
|
+
const { bottom } = useSafeAreaInsets()
|
|
108
|
+
return StyleSheet.create({
|
|
109
|
+
container: {
|
|
110
|
+
flex: 1,
|
|
111
|
+
justifyContent: 'center',
|
|
112
|
+
alignItems: 'center',
|
|
113
|
+
gap: 24,
|
|
114
|
+
paddingHorizontal: 16,
|
|
115
|
+
paddingBottom: bottom,
|
|
116
|
+
},
|
|
117
|
+
information: {
|
|
118
|
+
alignItems: 'center',
|
|
119
|
+
gap: 8,
|
|
120
|
+
},
|
|
121
|
+
heading: {
|
|
122
|
+
textAlign: 'center',
|
|
123
|
+
lineHeight: 20,
|
|
124
|
+
},
|
|
125
|
+
body: {
|
|
126
|
+
textAlign: 'center',
|
|
127
|
+
lineHeight: 20,
|
|
128
|
+
},
|
|
129
|
+
icon: {
|
|
130
|
+
color: theme.colors.iconColorDefaultDisabled,
|
|
131
|
+
},
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export default ErrorBoundary
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useTheme } from '@react-navigation/native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { StyleSheet, View } from 'react-native'
|
|
4
|
+
import { Spinner } from '../display'
|
|
5
|
+
|
|
6
|
+
export function DefaultLoading() {
|
|
7
|
+
const styles = useStyles()
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<View style={styles.container}>
|
|
11
|
+
<Spinner size={48} />
|
|
12
|
+
</View>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const useStyles = () => {
|
|
17
|
+
const theme = useTheme()
|
|
18
|
+
return StyleSheet.create({
|
|
19
|
+
container: {
|
|
20
|
+
flex: 1,
|
|
21
|
+
justifyContent: 'center',
|
|
22
|
+
alignItems: 'center',
|
|
23
|
+
},
|
|
24
|
+
loading: {
|
|
25
|
+
color: theme.colors.text,
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
}
|
package/src/navigation/index.tsx
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { StaticParamList } from '@react-navigation/native'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createNativeStackNavigator,
|
|
5
|
+
NativeStackHeaderLeftProps,
|
|
6
|
+
NativeStackHeaderRightProps,
|
|
7
|
+
} from '@react-navigation/native-stack'
|
|
4
8
|
import { NotFound } from '../screens/not_found'
|
|
5
9
|
import { ScreenLayout } from './screenLayout'
|
|
6
10
|
import { ConversationsScreen } from '../screens/conversations_screen'
|
|
@@ -14,21 +18,25 @@ import {
|
|
|
14
18
|
import { ReactionsScreen, ReactionsScreenOptions } from '../screens/reactions_screen'
|
|
15
19
|
|
|
16
20
|
export const ChatStack = createNativeStackNavigator({
|
|
21
|
+
screenOptions: {
|
|
22
|
+
headerBackButtonDisplayMode: 'minimal',
|
|
23
|
+
},
|
|
17
24
|
screenLayout: ScreenLayout,
|
|
18
25
|
screens: {
|
|
19
26
|
Conversations: {
|
|
20
27
|
screen: ConversationsScreen,
|
|
21
28
|
options: ({ route, navigation }) => ({
|
|
22
29
|
headerTitle: (route.params as { title?: string })?.title ?? 'Chat',
|
|
23
|
-
headerLeft: () => (
|
|
30
|
+
headerLeft: ({ tintColor }: NativeStackHeaderLeftProps) => (
|
|
24
31
|
<HeaderButton>
|
|
25
|
-
<Icon name="general.threeReducingHorizontalBars" size={18} />
|
|
32
|
+
<Icon name="general.threeReducingHorizontalBars" size={18} color={tintColor} />
|
|
26
33
|
</HeaderButton>
|
|
27
34
|
),
|
|
28
|
-
headerRight: () => (
|
|
35
|
+
headerRight: (props: NativeStackHeaderRightProps) => (
|
|
29
36
|
<HeaderBackButton
|
|
37
|
+
backImage={() => <Icon name="general.x" size={18} color={props.tintColor} />}
|
|
30
38
|
onPress={navigation.goBack}
|
|
31
|
-
|
|
39
|
+
{...props}
|
|
32
40
|
/>
|
|
33
41
|
),
|
|
34
42
|
}),
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import
|
|
3
|
-
import ErrorBoundary from '../components/error_boundary'
|
|
2
|
+
import ErrorBoundary from '../components/page/error_boundary'
|
|
4
3
|
import { Suspense } from 'react'
|
|
5
|
-
import { Text } from '../components/display'
|
|
6
4
|
import { ApiProvider } from '../contexts'
|
|
5
|
+
import { DefaultLoading } from '../components/page/loading'
|
|
7
6
|
|
|
8
7
|
export function ScreenLayout({ children }: { children: React.ReactElement }) {
|
|
9
8
|
return (
|
|
10
9
|
<ApiProvider>
|
|
11
|
-
<
|
|
12
|
-
{
|
|
13
|
-
|
|
14
|
-
<Suspense fallback={<Text>loading...</Text>}>{children}</Suspense>
|
|
15
|
-
</ErrorBoundary>
|
|
16
|
-
)}
|
|
17
|
-
</QueryErrorResetBoundary>
|
|
10
|
+
<ErrorBoundary>
|
|
11
|
+
<Suspense fallback={<DefaultLoading />}>{children}</Suspense>
|
|
12
|
+
</ErrorBoundary>
|
|
18
13
|
</ApiProvider>
|
|
19
14
|
)
|
|
20
15
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"error_boundary.d.ts","sourceRoot":"","sources":["../../src/components/error_boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAGhD,cAAM,aAAc,SAAQ,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC;IAAE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC,CAAC;IACtF,KAAK;;;MAGJ;IAED,iBAAiB,CAAC,KAAK,EAAE,GAAG;IAI5B,WAAW,CAAC,KAAK,EAAE,GAAG;IAItB,MAAM;CAOP;AAED,eAAe,aAAa,CAAA"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Text } from 'react-native';
|
|
3
|
-
class ErrorBoundary extends React.Component {
|
|
4
|
-
state = {
|
|
5
|
-
error: null,
|
|
6
|
-
unsubscriber: () => { },
|
|
7
|
-
};
|
|
8
|
-
componentDidCatch(error) {
|
|
9
|
-
this.handleError(error);
|
|
10
|
-
}
|
|
11
|
-
handleError(error) {
|
|
12
|
-
this.setState({ error });
|
|
13
|
-
}
|
|
14
|
-
render() {
|
|
15
|
-
if (this.state.error) {
|
|
16
|
-
return <Text>{JSON.stringify(this.state.error, null, 2)}</Text>;
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
return this.props.children;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
export default ErrorBoundary;
|
|
24
|
-
//# sourceMappingURL=error_boundary.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"error_boundary.js","sourceRoot":"","sources":["../../src/components/error_boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAA;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAEnC,MAAM,aAAc,SAAQ,KAAK,CAAC,SAAsD;IACtF,KAAK,GAAG;QACN,KAAK,EAAE,IAAI;QACX,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC;KACvB,CAAA;IAED,iBAAiB,CAAC,KAAU;QAC1B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;IAED,WAAW,CAAC,KAAU;QACpB,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1B,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QACjE,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAA;QAC5B,CAAC;IACH,CAAC;CACF;AAED,eAAe,aAAa,CAAA","sourcesContent":["import React, { PropsWithChildren } from 'react'\nimport { Text } from 'react-native'\n\nclass ErrorBoundary extends React.Component<PropsWithChildren<{ onReset?: () => void }>> {\n state = {\n error: null,\n unsubscriber: () => {},\n }\n\n componentDidCatch(error: any) {\n this.handleError(error)\n }\n\n handleError(error: any) {\n this.setState({ error })\n }\n\n render() {\n if (this.state.error) {\n return <Text>{JSON.stringify(this.state.error, null, 2)}</Text>\n } else {\n return this.props.children\n }\n }\n}\n\nexport default ErrorBoundary\n"]}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import React, { PropsWithChildren } from 'react'
|
|
2
|
-
import { Text } from 'react-native'
|
|
3
|
-
|
|
4
|
-
class ErrorBoundary extends React.Component<PropsWithChildren<{ onReset?: () => void }>> {
|
|
5
|
-
state = {
|
|
6
|
-
error: null,
|
|
7
|
-
unsubscriber: () => {},
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
componentDidCatch(error: any) {
|
|
11
|
-
this.handleError(error)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
handleError(error: any) {
|
|
15
|
-
this.setState({ error })
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
render() {
|
|
19
|
-
if (this.state.error) {
|
|
20
|
-
return <Text>{JSON.stringify(this.state.error, null, 2)}</Text>
|
|
21
|
-
} else {
|
|
22
|
-
return this.props.children
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default ErrorBoundary
|