Skip to content

Commit 9a0ab61

Browse files
antoniskrystofwoldrichlucas-zimerman
authored
feat(feedback): Theming (#4677)
* Update the client implementation to use the new capture feedback js api * Updates SDK API * Adds new feedback button in the sample * Adds changelog * Removes unused mock * Update CHANGELOG.md Co-authored-by: Krystof Woldrich <[email protected]> * Directly use captureFeedback from sentry/core * Use import from core * Fixes imports order lint issue * Fixes build issue * Adds captureFeedback tests from sentry-javascript * Update CHANGELOG.md * Only deprecate client captureUserFeedback * Add simple form UI * Adds basic form functionality * Update imports * Update imports * Remove useState hook to avoid multiple react instances issues * Move types and styles in different files * Removes attachment button to be added back separately along with the implementation * Add basic field validation * Adds changelog * Updates changelog * Updates changelog * Trim whitespaces from the submitted feedback * Adds tests * Renames FeedbackFormScreen to FeedbackForm * Add beta label * Extract default text to constants * Moves constant to a separate file and aligns naming with JS * Adds input text labels * Close screen before sending the feedback to minimise wait time Co-authored-by: LucasZF <[email protected]> * Rename file for consistency * Flatten configuration hierarchy and clean up * Align required values with JS * Use Sentry user email and name when set * Simplifies email validation * Show success alert message * Aligns naming with JS and unmounts the form by default * Use the minimum config without props in the changelog * Adds development not for unimplemented function * Show email and name conditionally * Adds sentry branding (png logo) * Adds sentry logo resource * Add assets in module exports * Revert "Add assets in module exports" This reverts commit 5292475. * Revert "Adds sentry logo resource" This reverts commit d6e9229. * Revert "Adds sentry branding (png logo)" This reverts commit 8c56753. * Add last event id * Mock lastEventId * Adds beta note in the changelog * Autoinject feedback form * Updates changelog * Align colors with JS * Update CHANGELOG.md Co-authored-by: Krystof Woldrich <[email protected]> * Update CHANGELOG.md Co-authored-by: Krystof Woldrich <[email protected]> * Update CHANGELOG.md Co-authored-by: Krystof Woldrich <[email protected]> * Use regular fonts for both buttons * Handle keyboard properly * Adds an option on whether the email should be validated * Merge properties only once * Loads current user data on form construction * Remove unneeded extra padding * Fix background color issue * Adds feedback button * Updates the changelog * Fixes changelog typo * Updates styles background color Co-authored-by: Krystof Woldrich <[email protected]> * Use defaultProps * Correct defaultProps * Adds test to verify when getUser is called * Use smaller image Co-authored-by: LucasZF <[email protected]> * Add margin next to the icon * Adds bottom spacing in the ErrorScreen so that the feedback button does not hide the scrollview buttons * (2.2) feat: Add Feedback Form UI Branding logo (#4357) * Adds sentry branding logo as a base64 encoded png --------- Co-authored-by: LucasZF <[email protected]> * Autoinject feedback form (#4370) * Align changelog entry * Update changelog * Disable bouncing * Add modal ui appearance * Update snapshot tests * Fix bottom margin * Fix sheet height * Remove extra modal border * Do not expose modal styles * Animate background color * Avoid keyboard in modal * Update changelog * Fix changelog * Updates comment * Extract FeedbackButtonProps * Add public function description to satisfy lint check * Adds tests * Fix tests * Add hardcoded dark and light color themes * Rename theme options * Update snapshot tests * Include in the feedback integration * Fix circular dependency * Add theme integration options * Adds changelog * Add comment note * Align with JS api * Remove unneeded line Co-authored-by: Krystof Woldrich <[email protected]> * Place widget button below the feedback widget shadow * Expose showFeedbackButton/hideFeedbackButton methods * Add dummy integration for tracking usage * Adds button border * Fixes tests * Add accentBackground and accentForeground colors * Extract integration getter in a helper function * Adds dynamic theming support * Add snapshot tests * Adds system theme tests * Test dynamically changed theme --------- Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: LucasZF <[email protected]>
1 parent cd6bf1f commit 9a0ab61

11 files changed

+3690
-155
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
### Features
1212

1313
- Adds the `FeedbackButton` component that shows the Feedback Widget ([#4378](https://github.com/getsentry/sentry-react-native/pull/4378))
14+
- Add Feedback Widget theming ([#4677](https://github.com/getsentry/sentry-react-native/pull/4677))
1415

1516
### Fixes
1617

packages/core/src/js/feedback/FeedbackButton.tsx

+27-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import * as React from 'react';
2-
import { Image, Text, TouchableOpacity } from 'react-native';
2+
import type { NativeEventSubscription} from 'react-native';
3+
import { Appearance, Image, Text, TouchableOpacity } from 'react-native';
34

45
import { defaultButtonConfiguration } from './defaults';
56
import { defaultButtonStyles } from './FeedbackWidget.styles';
7+
import { getTheme } from './FeedbackWidget.theme';
68
import type { FeedbackButtonProps, FeedbackButtonStyles, FeedbackButtonTextConfiguration } from './FeedbackWidget.types';
79
import { feedbackIcon } from './icons';
810
import { lazyLoadFeedbackIntegration } from './lazy';
@@ -18,20 +20,41 @@ const showFeedbackWidget = (): void => {
1820
* Implements a feedback button that opens the FeedbackForm.
1921
*/
2022
export class FeedbackButton extends React.Component<FeedbackButtonProps> {
23+
private _themeListener: NativeEventSubscription;
24+
2125
public constructor(props: FeedbackButtonProps) {
2226
super(props);
2327
lazyLoadFeedbackIntegration();
2428
}
2529

30+
/**
31+
* Adds a listener for theme changes.
32+
*/
33+
public componentDidMount(): void {
34+
this._themeListener = Appearance.addChangeListener(() => {
35+
this.forceUpdate();
36+
});
37+
}
38+
39+
/**
40+
* Removes the theme listener.
41+
*/
42+
public componentWillUnmount(): void {
43+
if (this._themeListener) {
44+
this._themeListener.remove();
45+
}
46+
}
47+
2648
/**
2749
* Renders the feedback button.
2850
*/
2951
public render(): React.ReactNode {
52+
const theme = getTheme();
3053
const text: FeedbackButtonTextConfiguration = { ...defaultButtonConfiguration, ...this.props };
3154
const styles: FeedbackButtonStyles = {
32-
triggerButton: { ...defaultButtonStyles.triggerButton, ...this.props.styles?.triggerButton },
33-
triggerText: { ...defaultButtonStyles.triggerText, ...this.props.styles?.triggerText },
34-
triggerIcon: { ...defaultButtonStyles.triggerIcon, ...this.props.styles?.triggerIcon },
55+
triggerButton: { ...defaultButtonStyles(theme).triggerButton, ...this.props.styles?.triggerButton },
56+
triggerText: { ...defaultButtonStyles(theme).triggerText, ...this.props.styles?.triggerText },
57+
triggerIcon: { ...defaultButtonStyles(theme).triggerIcon, ...this.props.styles?.triggerIcon },
3558
};
3659

3760
return (

packages/core/src/js/feedback/FeedbackWidget.styles.ts

+140-136
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,135 @@
11
import type { ViewStyle } from 'react-native';
22

3+
import type { FeedbackWidgetTheme } from './FeedbackWidget.theme';
34
import type { FeedbackButtonStyles, FeedbackWidgetStyles } from './FeedbackWidget.types';
45

5-
const PURPLE = 'rgba(88, 74, 192, 1)';
6-
const FOREGROUND_COLOR = '#2b2233';
7-
const BACKGROUND_COLOR = '#ffffff';
8-
const BORDER_COLOR = 'rgba(41, 35, 47, 0.13)';
9-
10-
const defaultStyles: FeedbackWidgetStyles = {
11-
container: {
12-
flex: 1,
13-
padding: 20,
14-
backgroundColor: BACKGROUND_COLOR,
15-
},
16-
title: {
17-
fontSize: 24,
18-
fontWeight: 'bold',
19-
marginBottom: 20,
20-
textAlign: 'left',
21-
flex: 1,
22-
color: FOREGROUND_COLOR,
23-
},
24-
label: {
25-
marginBottom: 4,
26-
fontSize: 16,
27-
color: FOREGROUND_COLOR,
28-
},
29-
input: {
30-
height: 50,
31-
borderColor: BORDER_COLOR,
32-
borderWidth: 1,
33-
borderRadius: 5,
34-
paddingHorizontal: 10,
35-
marginBottom: 15,
36-
fontSize: 16,
37-
color: FOREGROUND_COLOR,
38-
},
39-
textArea: {
40-
height: 100,
41-
textAlignVertical: 'top',
42-
color: FOREGROUND_COLOR,
43-
},
44-
screenshotButton: {
45-
backgroundColor: BACKGROUND_COLOR,
46-
padding: 15,
47-
borderRadius: 5,
48-
alignItems: 'center',
49-
flex: 1,
50-
borderWidth: 1,
51-
borderColor: BORDER_COLOR,
52-
},
53-
screenshotContainer: {
54-
flexDirection: 'row',
55-
alignItems: 'center',
56-
width: '100%',
57-
marginBottom: 20,
58-
},
59-
screenshotThumbnail: {
60-
width: 50,
61-
height: 50,
62-
borderRadius: 5,
63-
marginRight: 10,
64-
},
65-
screenshotText: {
66-
color: FOREGROUND_COLOR,
67-
fontSize: 16,
68-
},
69-
submitButton: {
70-
backgroundColor: PURPLE,
71-
paddingVertical: 15,
72-
borderRadius: 5,
73-
alignItems: 'center',
74-
marginBottom: 10,
75-
},
76-
submitText: {
77-
color: BACKGROUND_COLOR,
78-
fontSize: 18,
79-
},
80-
cancelButton: {
81-
backgroundColor: BACKGROUND_COLOR,
82-
padding: 15,
83-
borderRadius: 5,
84-
alignItems: 'center',
85-
borderWidth: 1,
86-
borderColor: BORDER_COLOR,
87-
},
88-
cancelText: {
89-
color: FOREGROUND_COLOR,
90-
fontSize: 16,
91-
},
92-
titleContainer: {
93-
flexDirection: 'row',
94-
width: '100%',
95-
},
96-
sentryLogo: {
97-
width: 40,
98-
height: 40,
99-
},
6+
const defaultStyles = (theme: FeedbackWidgetTheme): FeedbackWidgetStyles => {
7+
return {
8+
container: {
9+
flex: 1,
10+
padding: 20,
11+
backgroundColor: theme.background,
12+
},
13+
title: {
14+
fontSize: 24,
15+
fontWeight: 'bold',
16+
marginBottom: 20,
17+
textAlign: 'left',
18+
flex: 1,
19+
color: theme.foreground,
20+
},
21+
label: {
22+
marginBottom: 4,
23+
fontSize: 16,
24+
color: theme.foreground,
25+
},
26+
input: {
27+
height: 50,
28+
borderColor: theme.border,
29+
borderWidth: 1,
30+
borderRadius: 5,
31+
paddingHorizontal: 10,
32+
marginBottom: 15,
33+
fontSize: 16,
34+
color: theme.foreground,
35+
},
36+
textArea: {
37+
height: 100,
38+
textAlignVertical: 'top',
39+
color: theme.foreground,
40+
},
41+
screenshotButton: {
42+
backgroundColor: theme.background,
43+
padding: 15,
44+
borderRadius: 5,
45+
alignItems: 'center',
46+
flex: 1,
47+
borderWidth: 1,
48+
borderColor: theme.border,
49+
},
50+
screenshotContainer: {
51+
flexDirection: 'row',
52+
alignItems: 'center',
53+
width: '100%',
54+
marginBottom: 20,
55+
},
56+
screenshotThumbnail: {
57+
width: 50,
58+
height: 50,
59+
borderRadius: 5,
60+
marginRight: 10,
61+
},
62+
screenshotText: {
63+
color: theme.foreground,
64+
fontSize: 16,
65+
},
66+
submitButton: {
67+
backgroundColor: theme.accentBackground,
68+
paddingVertical: 15,
69+
borderRadius: 5,
70+
alignItems: 'center',
71+
marginBottom: 10,
72+
},
73+
submitText: {
74+
color: theme.accentForeground,
75+
fontSize: 18,
76+
},
77+
cancelButton: {
78+
backgroundColor: theme.background,
79+
padding: 15,
80+
borderRadius: 5,
81+
alignItems: 'center',
82+
borderWidth: 1,
83+
borderColor: theme.border,
84+
},
85+
cancelText: {
86+
color: theme.foreground,
87+
fontSize: 16,
88+
},
89+
titleContainer: {
90+
flexDirection: 'row',
91+
width: '100%',
92+
},
93+
sentryLogo: {
94+
width: 40,
95+
height: 40,
96+
tintColor: theme.sentryLogo,
97+
},
98+
};
10099
};
101100

102-
export const defaultButtonStyles: FeedbackButtonStyles = {
103-
triggerButton: {
104-
position: 'absolute',
105-
bottom: 30,
106-
right: 30,
107-
backgroundColor: BACKGROUND_COLOR,
108-
padding: 15,
109-
borderRadius: 40,
110-
justifyContent: 'center',
111-
alignItems: 'center',
112-
elevation: 5,
113-
shadowColor: BORDER_COLOR,
114-
shadowOffset: { width: 1, height: 2 },
115-
shadowOpacity: 0.5,
116-
shadowRadius: 3,
117-
flexDirection: 'row',
118-
borderWidth: 1,
119-
borderColor: BORDER_COLOR,
120-
},
121-
triggerText: {
122-
color: FOREGROUND_COLOR,
123-
fontSize: 18,
124-
},
125-
triggerIcon: {
126-
width: 24,
127-
height: 24,
128-
padding: 2,
129-
marginEnd: 6,
130-
},
101+
export const defaultButtonStyles = (theme: FeedbackWidgetTheme): FeedbackButtonStyles => {
102+
return {
103+
triggerButton: {
104+
position: 'absolute',
105+
bottom: 30,
106+
right: 30,
107+
backgroundColor: theme.background,
108+
padding: 15,
109+
borderRadius: 40,
110+
justifyContent: 'center',
111+
alignItems: 'center',
112+
elevation: 5,
113+
shadowColor: theme.border,
114+
shadowOffset: { width: 1, height: 2 },
115+
shadowOpacity: 0.5,
116+
shadowRadius: 3,
117+
flexDirection: 'row',
118+
borderWidth: 1,
119+
borderColor: theme.border,
120+
},
121+
triggerText: {
122+
color: theme.foreground,
123+
fontSize: 18,
124+
},
125+
triggerIcon: {
126+
width: 24,
127+
height: 24,
128+
padding: 2,
129+
marginEnd: 6,
130+
tintColor: theme.sentryLogo,
131+
},
132+
};
131133
};
132134

133135
export const modalWrapper: ViewStyle = {
@@ -138,18 +140,20 @@ export const modalWrapper: ViewStyle = {
138140
bottom: 0,
139141
};
140142

141-
export const modalSheetContainer: ViewStyle = {
142-
backgroundColor: '#ffffff',
143-
borderTopLeftRadius: 16,
144-
borderTopRightRadius: 16,
145-
overflow: 'hidden',
146-
alignSelf: 'stretch',
147-
shadowColor: '#000',
148-
shadowOffset: { width: 0, height: -3 },
149-
shadowOpacity: 0.1,
150-
shadowRadius: 4,
151-
elevation: 5,
152-
flex: 1,
143+
export const modalSheetContainer = (theme: FeedbackWidgetTheme): ViewStyle => {
144+
return {
145+
backgroundColor: theme.background,
146+
borderTopLeftRadius: 16,
147+
borderTopRightRadius: 16,
148+
overflow: 'hidden',
149+
alignSelf: 'stretch',
150+
shadowColor: '#000',
151+
shadowOffset: { width: 0, height: -3 },
152+
shadowOpacity: 0.1,
153+
shadowRadius: 4,
154+
elevation: 5,
155+
flex: 1,
156+
};
153157
};
154158

155159
export const topSpacer: ViewStyle = {

0 commit comments

Comments
 (0)