Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Report a Problem functionality #8605

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion .github/actions/prepare-ios-build/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ runs:
echo "::endgroup::"

- name: Cache Pods
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/prepare-mobile-build/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ runs:
working-directory: ./fastlane

- name: Cache Ruby gems
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/prepare-node-deps/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ runs:
echo "::endgroup::"

- name: Cache Node.js modules
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
Expand Down
118 changes: 118 additions & 0 deletions app/components/button/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {fireEvent, render} from '@testing-library/react-native';
import React from 'react';
import {View, Text} from 'react-native';

import {Preferences} from '@constants';

import Button from './index';

describe('components/button', () => {
const theme: Theme = Preferences.THEMES.denim;

it('should render button with text', () => {
const {getByText} = render(
<Button
onPress={jest.fn()}
text='Test Button'
theme={theme}
/>,
);

expect(getByText('Test Button')).toBeTruthy();
});

it('should handle onPress', () => {
const onPress = jest.fn();
const {getByTestId} = render(
<Button
onPress={onPress}
text='Test Button'
theme={theme}
testID='test-button'
/>,
);

fireEvent.press(getByTestId('test-button'));
expect(onPress).toHaveBeenCalled();
});

it('should render with icon', () => {
const {getByTestId} = render(
<Button
onPress={jest.fn()}
text='Test Button'
theme={theme}
iconName='close'
iconSize={24}
testID='test-button'
/>,
);

const icon = getByTestId('test-button-icon');
expect(icon).toBeTruthy();
expect(icon.props.name).toBe('close');
});

it('should render disabled button', () => {
const onPress = jest.fn();
const {getByTestId} = render(
<Button
onPress={onPress}
text='Test Button'
theme={theme}
disabled={true}
testID='test-button'
/>,
);

fireEvent.press(getByTestId('test-button'));
expect(onPress).not.toHaveBeenCalled();
});

it('should render icon on the right', () => {
const props = {
onPress: jest.fn(),
text: 'Test Button',
theme,
iconName: 'close',
iconSize: 24,
isIconOnTheRight: false,
testID: 'test-button',
};

const {getByTestId, rerender} = render(<Button {...props}/>);

const container = getByTestId('test-button-text-container');

// When icon is on the left, it should be the first child
expect(container.children[0].props.testID).toEqual('test-button-icon');

props.isIconOnTheRight = true;
rerender(<Button {...props}/>);

// When icon is on the right, it should be the last child
expect(container.children[1].props.testID).toEqual('test-button-icon');
});

it('should render custom icon component', () => {
const CustomIcon = () => (
<View testID='custom-icon'>
<Text>{'Custom Icon'}</Text>
</View>
);
const {getByTestId} = render(
<Button
onPress={jest.fn()}
text='Test Button'
theme={theme}
iconComponent={<CustomIcon/>}
testID='test-button'
/>,
);

expect(getByTestId('custom-icon')).toBeTruthy();
});
});
18 changes: 13 additions & 5 deletions app/components/button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ type Props = ConditionalProps & {
iconComponent?: ReactNode;
disabled?: boolean;
hitSlop?: Insets;
isIconOnTheRight?: boolean;
};

const styles = StyleSheet.create({
container: {flexDirection: 'row'},
icon: {marginRight: 7},
container: {
flexDirection: 'row',
gap: 7,
},
});

const Button = ({
Expand All @@ -47,6 +50,7 @@ const Button = ({
testID,
iconName,
iconSize,
isIconOnTheRight = false,
iconComponent,
disabled,
hitSlop,
Expand Down Expand Up @@ -88,7 +92,7 @@ const Button = ({
name={iconName!}
size={iconSize}
color={StyleSheet.flatten(txtStyle).color}
style={styles.icon}
testID={`${testID}-icon`}
/>
);
}
Expand All @@ -102,14 +106,18 @@ const Button = ({
disabled={disabled}
hitSlop={hitSlop}
>
<View style={textContainerStyle}>
{icon}
<View
style={textContainerStyle}
testID={`${testID}-text-container`}
>
{!isIconOnTheRight && icon}
<Text
style={txtStyle}
numberOfLines={1}
>
{text}
</Text>
{isIconOnTheRight && icon}
</View>
</ElementButton>
);
Expand Down
52 changes: 52 additions & 0 deletions app/components/menu_divider/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {render} from '@testing-library/react-native';
import React from 'react';

import {Preferences} from '@constants';

import MenuDivider from './index';

describe('components/menu_divider', () => {
const theme = Preferences.THEMES.denim;

it('should render divider with default margins', () => {
const {root} = render(<MenuDivider/>);

expect(root).toHaveStyle({
marginTop: 8,
marginBottom: 8,
marginLeft: 0,
marginRight: 0,
});
});

it('should render divider with custom margins', () => {
const margins = {
marginTop: 16,
marginBottom: 24,
marginLeft: 12,
marginRight: 13,
};

const {root} = render(<MenuDivider {...margins}/>);

expect(root).toHaveStyle({
marginTop: 16,
marginBottom: 24,
marginLeft: 12,
marginRight: 13,
});
});

it('should apply correct theme styles', () => {
const {root} = render(<MenuDivider/>);

expect(root).toHaveStyle({
backgroundColor: theme.centerChannelColor,
height: 1,
opacity: 0.08,
});
});
});
38 changes: 38 additions & 0 deletions app/components/menu_divider/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import React, {useMemo} from 'react';
import {View} from 'react-native';

import {useTheme} from '@context/theme';
import {makeStyleSheetFromTheme} from '@utils/theme';

const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
divider: {
backgroundColor: theme.centerChannelColor,
height: 1,
opacity: 0.08,
},
}));

type Props = {
marginTop?: number;
marginBottom?: number;
marginLeft?: number;
marginRight?: number;
}

// Menu divider as per https://www.figma.com/design/ZV4NeVyUZoKfKRcRGyFJiT/Components---Mobile---Menu-Divider?node-id=1215-1535&t=qHU2DwCWm5cSbiq4-0
const MenuDivider = ({marginTop = 8, marginBottom = 8, marginLeft = 0, marginRight = 0}: Props) => {
const theme = useTheme();
const styles = getStyleSheet(theme);

const style = useMemo(() => [
styles.divider,
{marginTop, marginBottom, marginLeft, marginRight},
], [styles.divider, marginTop, marginBottom, marginLeft, marginRight]);

return (<View style={style}/>);
};

export default MenuDivider;
24 changes: 9 additions & 15 deletions app/components/section_notice/__snapshots__/index.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -171,22 +171,20 @@ exports[`Section notice match snapshot 1`] = `
[
{
"flexDirection": "row",
"gap": 7,
},
{
"minHeight": 18,
},
]
}
testID="undefined-text-container"
>
<Icon
color="#ffffff"
name="chevron-right"
size={18}
style={
{
"marginRight": 7,
}
}
testID="undefined-icon"
/>
<Text
numberOfLines={1}
Expand Down Expand Up @@ -293,22 +291,20 @@ exports[`Section notice match snapshot 1`] = `
[
{
"flexDirection": "row",
"gap": 7,
},
{
"minHeight": 18,
},
]
}
testID="undefined-text-container"
>
<Icon
color="#1c58d9"
name="chevron-right"
size={18}
style={
{
"marginRight": 7,
}
}
testID="undefined-icon"
/>
<Text
numberOfLines={1}
Expand Down Expand Up @@ -415,22 +411,20 @@ exports[`Section notice match snapshot 1`] = `
[
{
"flexDirection": "row",
"gap": 7,
},
{
"minHeight": 18,
},
]
}
testID="undefined-text-container"
>
<Icon
color="#1c58d9"
name="chevron-right"
size={18}
style={
{
"marginRight": 7,
}
}
testID="undefined-icon"
/>
<Text
numberOfLines={1}
Expand Down
2 changes: 2 additions & 0 deletions app/constants/screens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const PINNED_MESSAGES = 'PinnedMessages';
export const POST_OPTIONS = 'PostOptions';
export const POST_PRIORITY_PICKER = 'PostPriorityPicker';
export const REACTIONS = 'Reactions';
export const REPORT_PROBLEM = 'ReportProblem';
export const REVIEW_APP = 'ReviewApp';
export const SAVED_MESSAGES = 'SavedMessages';
export const SEARCH = 'Search';
Expand Down Expand Up @@ -132,6 +133,7 @@ export default {
POST_OPTIONS,
POST_PRIORITY_PICKER,
REACTIONS,
REPORT_PROBLEM,
REVIEW_APP,
SAVED_MESSAGES,
SEARCH,
Expand Down
Loading
Loading