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

feat(design-v2): add feedback flow in react native dogfood #1551

Merged
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
19 changes: 19 additions & 0 deletions sample-apps/react-native/dogfood/src/assets/Close.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { Svg, Path } from 'react-native-svg';
import { ColorValue } from 'react-native/types';

type Props = {
color: ColorValue;
size: number;
};

const Close = ({ color, size }: Props) => (
<Svg viewBox={'0 0 24 24'} width={size} height={size}>
<Path
d="M18.2997 5.70997C17.9097 5.31997 17.2797 5.31997 16.8897 5.70997L11.9997 10.59L7.10973 5.69997C6.71973 5.30997 6.08973 5.30997 5.69973 5.69997C5.30973 6.08997 5.30973 6.71997 5.69973 7.10997L10.5897 12L5.69973 16.89C5.30973 17.28 5.30973 17.91 5.69973 18.3C6.08973 18.69 6.71973 18.69 7.10973 18.3L11.9997 13.41L16.8897 18.3C17.2797 18.69 17.9097 18.69 18.2997 18.3C18.6897 17.91 18.6897 17.28 18.2997 16.89L13.4097 12L18.2997 7.10997C18.6797 6.72997 18.6797 6.08997 18.2997 5.70997Z"
fill={color}
/>
</Svg>
);

export default Close;
19 changes: 19 additions & 0 deletions sample-apps/react-native/dogfood/src/assets/Star.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { Svg, Path } from 'react-native-svg';
import { ColorValue } from 'react-native/types';

type Props = {
color: ColorValue;
size: number;
};

const Star = ({ color, size }: Props) => (
<Svg viewBox={'0 0 68 67'} width={size} height={size}>
<Path
d="M40.8853 26.8323L36.7203 13.3206C35.8987 10.6685 32.102 10.6685 31.3087 13.3206L27.1153 26.8323H14.507C11.7587 26.8323 10.6253 30.3219 12.8637 31.8852L23.177 39.1435L19.1253 52.0131C18.3037 54.6094 21.3637 56.7031 23.5453 55.056L34.0003 47.2394L44.4553 55.0839C46.637 56.731 49.697 54.6373 48.8753 52.041L44.8237 39.1714L55.137 31.9131C57.3753 30.3219 56.242 26.8602 53.4937 26.8602H40.8853V26.8323Z"
fill={color}
/>
</Svg>
);

export default Star;
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { MoreActionsButton } from './MoreActionsButton';
import { ParticipantsButton } from './ParticipantsButton';
import { ChatButton } from './ChatButton';
import { RecordCallButton } from './RecordCallButton';
import { AudioButton } from './AudioButton';

export type BottomControlsProps = Pick<
CallContentProps,
Expand Down Expand Up @@ -49,7 +48,6 @@ export const BottomControls = ({
<View style={[styles.callControlsWrapper]}>
<View style={styles.left}>
<MoreActionsButton />
<AudioButton />
<ToggleAudioPublishingButton />
<ToggleVideoPublishingButton />
<RecordCallButton
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React, { useState } from 'react';
import {
CallControlsButton,
useCall,
useTheme,
} from '@stream-io/video-react-native-sdk';
import { IconWrapper } from '@stream-io/video-react-native-sdk/src/icons';
import MoreActions from '../../assets/MoreActions';
import NoiseCancelation from '../../assets/NoiseCancelation';
import ClosedCaptions from '../../assets/ClosedCaptions';
import { BottomControlsDrawer, DrawerOption } from '../BottomControlsDrawer';
import Stats from '../../assets/Stats';
import Feedback from '../../assets/Feedback';
import FeedbackModal from '../FeedbackModal';

/**
* The props for the More Actions Button in the Call Controls.
Expand All @@ -30,39 +30,25 @@ export const MoreActionsButton = ({
onPressHandler,
}: MoreActionsButtonProps) => {
const {
theme: { colors, moreActionsButton, defaults, variants },
theme: { colors, variants, moreActionsButton, defaults },
} = useTheme();
const [isDrawerVisible, setIsDrawerVisible] = useState(false);
const [feedbackModalVisible, setFeedbackModalVisible] = useState(false);
const call = useCall();

const handleRating = async (rating: number) => {
await call
?.submitFeedback(Math.min(Math.max(1, rating), 5), {
reason: '<no-message-provided>',
})
.catch((err) => console.warn('Failed to submit call feedback', err));

setFeedbackModalVisible(false);
};

const options: DrawerOption[] = [
{
id: '1',
label: 'Noise Cancellation On',
icon: (
<IconWrapper>
<NoiseCancelation
color={colors.iconPrimaryDefault}
size={variants.roundButtonSizes.sm}
/>
</IconWrapper>
),
onPress: () => {},
},
{
id: '2',
label: 'Start Closed Captions',
icon: (
<IconWrapper>
<ClosedCaptions
color={colors.iconPrimaryDefault}
size={variants.roundButtonSizes.sm}
/>
</IconWrapper>
),
onPress: () => {},
},
{
id: '3',
label: 'Stats',
icon: (
<IconWrapper>
Expand All @@ -75,7 +61,7 @@ export const MoreActionsButton = ({
onPress: () => {},
},
{
id: '4',
id: '2',
label: 'Feedback',
icon: (
<IconWrapper>
Expand All @@ -85,7 +71,10 @@ export const MoreActionsButton = ({
/>
</IconWrapper>
),
onPress: () => {},
onPress: () => {
setIsDrawerVisible(false);
setFeedbackModalVisible(true);
},
},
];

Expand All @@ -109,6 +98,11 @@ export const MoreActionsButton = ({
onClose={() => setIsDrawerVisible(false)}
options={options}
/>
<FeedbackModal
visible={feedbackModalVisible}
onClose={() => setFeedbackModalVisible(false)}
onRating={handleRating}
/>
<IconWrapper>
<MoreActions
color={colors.iconPrimaryDefault}
Expand Down
197 changes: 197 additions & 0 deletions sample-apps/react-native/dogfood/src/components/FeedbackModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import { IconWrapper } from '@stream-io/video-react-native-sdk/src/icons';
import React, { useMemo, useState } from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Modal,
Image,
} from 'react-native';
import Star from '../assets/Star';
import { useTheme } from '@stream-io/video-react-native-sdk';
import Close from '../assets/Close';
import { FEEDBACK_MODAL_MAX_WIDTH } from '../constants';

interface FeedbackModalProps {
visible: boolean;
onClose: () => void;
onRating: (rating: number) => void;
}

const FeedbackModal: React.FC<FeedbackModalProps> = ({
visible,
onClose,
onRating,
}) => {
const styles = useStyles();
const {
theme: { colors, variants },
} = useTheme();
const [selectedRating, setSelectedRating] = useState<number | null>(null);

const handleRatingPress = (rating: number) => {
setSelectedRating(rating);
onRating(rating);
};

return (
<Modal
transparent
visible={visible}
onRequestClose={onClose}
supportedOrientations={['portrait', 'landscape']}
>
<TouchableOpacity style={styles.overlay} onPress={onClose}>
<View style={[styles.modal]}>
<View style={styles.top}>
<View style={styles.topRight}>
<TouchableOpacity onPress={onClose} style={[styles.closeButton]}>
<IconWrapper>
<Close
color={colors.typeSecondary}
size={variants.roundButtonSizes.sm}
/>
</IconWrapper>
</TouchableOpacity>
</View>
</View>
<Image
source={require('../assets/feedbackLogo.png')}
style={styles.logo}
/>
<View style={styles.textContainer}>
<Text style={styles.title}>We Value Your Feedback!</Text>
<Text style={styles.subtitle}>
Tell us about your video call experience.
</Text>
</View>
<View style={styles.ratingContainer}>
{[1, 2, 3, 4, 5].map((rating) => (
<TouchableOpacity
key={rating}
onPress={() => handleRatingPress(rating)}
style={[styles.ratingButton]}
>
<IconWrapper>
<Star
color={
selectedRating && selectedRating >= rating
? colors.iconAlertSuccess
: colors.typeSecondary
}
size={68}
/>
</IconWrapper>
</TouchableOpacity>
))}
</View>
<View style={styles.bottom}>
<View style={styles.left}>
<Text style={styles.text}>Very Bad</Text>
</View>
<View style={styles.right}>
<Text style={styles.text}>Very Good</Text>
</View>
</View>
</View>
</TouchableOpacity>
</Modal>
);
};

const useStyles = () => {
const {
theme: { colors, variants },
} = useTheme();
return useMemo(
() =>
StyleSheet.create({
overlay: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
modal: {
width: '90%',
backgroundColor: colors.sheetSecondary,
borderRadius: variants.borderRadiusSizes.lg,
alignItems: 'center',
paddingHorizontal: variants.spacingSizes.md,
paddingVertical: variants.spacingSizes.md,
maxWidth: FEEDBACK_MODAL_MAX_WIDTH,
},
top: {
flex: 1,
marginBottom: variants.spacingSizes.lg,
flexDirection: 'row',
},
closeButton: {
backgroundColor: colors.buttonSecondaryDefault,
borderRadius: variants.borderRadiusSizes.xl,
width: variants.roundButtonSizes.md,
height: variants.roundButtonSizes.md,
},
topRight: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
},
logo: {
width: 190,
height: 134,
marginBottom: variants.spacingSizes.md,
alignSelf: 'center',
},
textContainer: {
maxWidth: 230,
textAlign: 'center',
},
title: {
fontSize: 28,
marginBottom: variants.spacingSizes.sm,
textAlign: 'center',
color: 'white',
fontWeight: '600',
},
subtitle: {
fontSize: 13,
textAlign: 'center',
color: colors.typeSecondary,
marginBottom: variants.spacingSizes.xl,
fontWeight: '600',
},
ratingContainer: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: variants.spacingSizes.md,
},
ratingButton: {
paddingVertical: variants.spacingSizes.md,
},
bottom: {
display: 'flex',
flexDirection: 'row',
marginTop: variants.spacingSizes.xl,
},
left: {
flex: 1,
flexDirection: 'row',
alignItems: 'flex-start',
},
right: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
},
text: {
color: colors.typeSecondary,
fontSize: 13,
fontWeight: '500',
},
}),
[variants, colors],
);
};

export default FeedbackModal;
1 change: 1 addition & 0 deletions sample-apps/react-native/dogfood/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const BUTTON_HEIGHT = 50;
export const INPUT_HEIGHT = 50;
export const AVATAR_SIZE = 50;
export const BOTTOM_CONTROLS_HEIGHT = 76;
export const FEEDBACK_MODAL_MAX_WIDTH = 385;

export const Z_INDEX = {
IN_BACK: 0,
Expand Down
Loading