Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/pluggableWidgets/feedback-native/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Added

- Translation support for all widget text through configurable properties in Studio Pro.
- Visible label above feedback input field to ensure WCAG compliance.

### Fixed

- Fixed logo overlap issue where custom logo appeared on top of default icon instead of replacing it.

## [3.4.0] - 2025-3-31

### Changed
Expand Down
2 changes: 1 addition & 1 deletion packages/pluggableWidgets/feedback-native/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "feedback-native",
"widgetName": "Feedback",
"version": "3.4.0",
"version": "3.4.1",
"license": "Apache-2.0",
"repository": {
"type": "git",
Expand Down
44 changes: 29 additions & 15 deletions packages/pluggableWidgets/feedback-native/src/Feedback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,17 @@ export class Feedback extends Component<FeedbackProps<FeedbackStyle>, State> {
return this.state.status === "initial" ? (
<View style={floatingButtonContainer(this.state.deviceHeight)}>
<View style={this.styles.floatingButton}>
<TouchableOpacity onPress={this.onFeedbackButtonPressHandler} testID={`${this.props.name}$button`}>
<TouchableOpacity
onPress={this.onFeedbackButtonPressHandler}
testID={`${this.props.name}$button`}
accessibilityRole="button"
accessibilityLabel={this.props.accessibilityLabelFeedbackButton?.value ?? "Open feedback form"}
>
{this.props.logo && this.props.logo.value ? (
<Image style={imageStyle as StyleProp<SvgImageStyle>} source={this.props.logo.value} />
) : null}
<RNImage style={imageStyle} source={commentIcon} />
) : (
<RNImage style={imageStyle} source={commentIcon} />
)}
</TouchableOpacity>
</View>
</View>
Expand All @@ -121,19 +127,27 @@ export class Feedback extends Component<FeedbackProps<FeedbackStyle>, State> {
}}
{...this.dialogContainerProps}
>
<Dialog.Title style={this.styles.title}>Send Feedback</Dialog.Title>
<Dialog.Title style={this.styles.title}>
{this.props.titleSendFeedback?.value ?? "Send Feedback"}
</Dialog.Title>
<Text style={{ marginTop: 12, marginBottom: 8, fontSize: 14 }}>
{this.props.labelFeedbackInput?.value ?? "Type your feedback here"}
</Text>
<TextInput
testID={`${this.props.name}$input`}
multiline
style={this.processedStyles.textAreaInputStyles}
value={this.state.feedbackMessage}
onChangeText={this.onChangeTextHandler}
placeholder="Type your feedback here"
placeholder={this.props.placeholderFeedback?.value ?? "Type your feedback here"}
accessibilityLabel={this.props.labelFeedbackInput?.value ?? "Type your feedback here"}
{...this.processedStyles.textAreaInputProps}
/>
{this.props.allowScreenshot && (
<View style={switchContainer}>
<Text style={this.styles.switchLabel}>Include Screenshot</Text>
<Text style={this.styles.switchLabel}>
{this.props.labelIncludeScreenshot?.value ?? "Include Screenshot"}
</Text>
<Switch
testID={`${this.props.name}$switch`}
style={this.processedStyles.switchInputStyles}
Expand All @@ -145,13 +159,13 @@ export class Feedback extends Component<FeedbackProps<FeedbackStyle>, State> {
</View>
)}
<Dialog.Button
label="Cancel"
label={this.props.buttonCancel?.value ?? "Cancel"}
color={this.styles.button.color}
onPress={this.onCancelHandler}
testID={`${this.props.name}$cancel`}
/>
<Dialog.Button
label="Send"
label={this.props.buttonSend?.value ?? "Send"}
disabled={disabled}
color={sendButtonColor}
onPress={this.onSendHandler}
Expand All @@ -164,7 +178,7 @@ export class Feedback extends Component<FeedbackProps<FeedbackStyle>, State> {
private renderInProgressDialog(): JSX.Element {
return (
<Dialog.Container visible={this.state.status === "inprogress"} {...this.dialogContainerProps}>
<Dialog.Title style={this.styles.title}>Sending...</Dialog.Title>
<Dialog.Title style={this.styles.title}>{this.props.titleSending?.value ?? "Sending..."}</Dialog.Title>
<ActivityIndicator
color={this.styles.activityIndicator.color}
size="large"
Expand All @@ -177,12 +191,12 @@ export class Feedback extends Component<FeedbackProps<FeedbackStyle>, State> {
private renderDoneDialog(): JSX.Element {
return (
<Dialog.Container visible={this.state.status === "done"} {...this.dialogContainerProps}>
<Dialog.Title style={this.styles.title}>Result</Dialog.Title>
<Dialog.Title style={this.styles.title}>{this.props.titleResult?.value ?? "Result"}</Dialog.Title>
<Dialog.Description style={this.processedStyles.descriptionStyle} testID={`${this.props.name}$success`}>
Feedback successfully sent
{this.props.messageSuccess?.value ?? "Feedback successfully sent"}
</Dialog.Description>
<Dialog.Button
label="OK"
label={this.props.buttonOk?.value ?? "OK"}
onPress={this.onCancelHandler}
color={this.styles.button.color}
testID={`${this.props.name}$success$ok`}
Expand All @@ -194,12 +208,12 @@ export class Feedback extends Component<FeedbackProps<FeedbackStyle>, State> {
private renderErrorDialog(): JSX.Element {
return (
<Dialog.Container visible={this.state.status === "error"} {...this.dialogContainerProps}>
<Dialog.Title style={this.styles.title}>Result</Dialog.Title>
<Dialog.Title style={this.styles.title}>{this.props.titleResult?.value ?? "Result"}</Dialog.Title>
<Dialog.Description style={this.processedStyles.descriptionStyle} testID={`${this.props.name}$error`}>
Error sending feedback
{this.props.messageError?.value ?? "Error sending feedback"}
</Dialog.Description>
<Dialog.Button
label="OK"
label={this.props.buttonOk?.value ?? "OK"}
onPress={this.onCancelHandler}
color={this.styles.button.color}
testID={`${this.props.name}$error$ok`}
Expand Down
125 changes: 109 additions & 16 deletions packages/pluggableWidgets/feedback-native/src/Feedback.xml
Original file line number Diff line number Diff line change
@@ -1,24 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<widget id="com.mendix.widget.native.feedback.Feedback" supportedPlatform="Native" needsEntityContext="true" offlineCapable="true" pluginWidget="true" xmlns="http://www.mendix.com/widget/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mendix.com/widget/1.0/ ../../../node_modules/mendix/custom_widget.xsd">
<name>Feedback</name>
<description>Allow users to submit feedback directly into the app project.</description>
<studioProCategory>Add-ons</studioProCategory>
<studioCategory>Add-ons</studioCategory>
<properties>
<property key="sprintrapp" type="string">
<caption>App ID</caption>
<category>General</category>
<description>The App ID is a hash that uniquely identifies your app project. You can find this ID in Settings > General in the Developer Portal.</description>
</property>
<property key="allowScreenshot" type="boolean" defaultValue="true">
<caption>Allow screenshots</caption>
<category>General</category>
<description>If you are not allowed to send screenshots when submitting feedback for legal reasons, set this to ‘No’.</description>
</property>
<property key="logo" type="image" required="false">
<caption>Logo</caption>
<category>General</category>
<description>For customized branding, add a logo to the widget. The recommended size of the image is 90 by 90 pixels.</description>
</property>
<propertyGroup caption="General">
<property key="sprintrapp" type="string">
<caption>App ID</caption>
<description>The App ID is a hash that uniquely identifies your app project. You can find this ID in Settings > General in the Developer Portal.</description>
</property>
<property key="allowScreenshot" type="boolean" defaultValue="true">
<caption>Allow screenshots</caption>
<description>If you are not allowed to send screenshots when submitting feedback for legal reasons, set this to ‘No’.</description>
</property>
<property key="logo" type="image" required="false">
<caption>Logo</caption>
<description>For customized branding, add a logo to the widget. The recommended size of the image is 90 by 90 pixels.</description>
</property>
</propertyGroup>
<propertyGroup caption="Localization">
<propertyGroup caption="Dialog Titles">
<property key="titleSendFeedback" type="textTemplate" required="false">
<caption>Send feedback title</caption>
<description>Title shown when composing feedback</description>
<translations>
<translation lang="en_US">Send Feedback</translation>
</translations>
</property>
<property key="titleSending" type="textTemplate" required="false">
<caption>Sending title</caption>
<description>Title shown while sending feedback</description>
<translations>
<translation lang="en_US">Sending...</translation>
</translations>
</property>
<property key="titleResult" type="textTemplate" required="false">
<caption>Result title</caption>
<description>Title shown in result dialogs (success/error)</description>
<translations>
<translation lang="en_US">Result</translation>
</translations>
</property>
</propertyGroup>
<propertyGroup caption="Input Labels">
<property key="labelFeedbackInput" type="textTemplate" required="false">
<caption>Feedback input label</caption>
<description>Visible label shown above the feedback text field</description>
<translations>
<translation lang="en_US">Type your feedback here</translation>
</translations>
</property>
<property key="placeholderFeedback" type="textTemplate" required="false">
<caption>Feedback placeholder</caption>
<description>Placeholder text for feedback input field</description>
<translations>
<translation lang="en_US">Type your feedback here</translation>
</translations>
</property>
<property key="labelIncludeScreenshot" type="textTemplate" required="false">
<caption>Screenshot label</caption>
<description>Label for screenshot toggle switch</description>
<translations>
<translation lang="en_US">Include Screenshot</translation>
</translations>
</property>
</propertyGroup>
<propertyGroup caption="Buttons">
<property key="buttonCancel" type="textTemplate" required="false">
<caption>Cancel button</caption>
<description>Label for cancel button</description>
<translations>
<translation lang="en_US">Cancel</translation>
</translations>
</property>
<property key="buttonSend" type="textTemplate" required="false">
<caption>Send button</caption>
<description>Label for send button</description>
<translations>
<translation lang="en_US">Send</translation>
</translations>
</property>
<property key="buttonOk" type="textTemplate" required="false">
<caption>OK button</caption>
<description>Label for OK button in result dialogs</description>
<translations>
<translation lang="en_US">OK</translation>
</translations>
</property>
<property key="accessibilityLabelFeedbackButton" type="textTemplate" required="false">
<caption>Feedback button accessibility label</caption>
<description>Label announced by screen readers for the feedback button (not visible on screen)</description>
<translations>
<translation lang="en_US">Open feedback form</translation>
</translations>
</property>
</propertyGroup>
<propertyGroup caption="Messages">
<property key="messageSuccess" type="textTemplate" required="false">
<caption>Success message</caption>
<description>Message shown when feedback is sent successfully</description>
<translations>
<translation lang="en_US">Feedback successfully sent</translation>
</translations>
</property>
<property key="messageError" type="textTemplate" required="false">
<caption>Error message</caption>
<description>Message shown when feedback fails to send</description>
<translations>
<translation lang="en_US">Error sending feedback</translation>
</translations>
</property>
</propertyGroup>
</propertyGroup>
</properties>
</widget>
Loading
Loading