Skip to content

Instantly share code, notes, and snippets.

@kukiron
Created April 9, 2020 08:30
Show Gist options
  • Save kukiron/efcae2776e2b0add0c85cef60d9fa622 to your computer and use it in GitHub Desktop.
Save kukiron/efcae2776e2b0add0c85cef60d9fa622 to your computer and use it in GitHub Desktop.
Component to show shared file list between users or in groups
import flatten from 'lodash/flatten';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import {
StyleSheet,
FlatList,
SectionList,
TouchableOpacity,
ActivityIndicator,
} from 'react-native';
import {
View,
Container,
Tab,
Tabs,
Text,
} from 'native-base';
import { translateString } from 'yeppik-common/lib/i18n';
import { H2 } from './translated';
import { Media, Document } from '../conversation/conversation/attachment/PreviewInList';
import dimensions from '../../common/dimensions';
import { getFilesWithTimeLine } from '../../common/dates';
import { getDownloadedAttachments, navigateToAttachment } from '../../common/attachments';
import { playClicker } from '../../actions/sounds';
import variables from '../../theme/variables/platform';
const mediaDimension = dimensions.attachment.gallery.display;
const styles = StyleSheet.create({
view: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF',
},
tabBarUnderline: {
height: 0,
},
tab: {
backgroundColor: '#FFFFFF',
},
text: {
color: '#00536C',
},
activeTab: {
borderBottomColor: '#00536C',
borderBottomWidth: 2,
backgroundColor: '#F5F5F5',
},
containerHeader: {
marginTop: 10,
marginBottom: 10,
marginLeft: 10,
},
mediaContainer: {
margin: variables.sharedMediaGallery.margin,
marginTop: 0,
width: variables.deviceWidth,
paddingBottom: 30,
},
documentContainer: {
paddingBottom: 30,
},
mediaFile: {
borderWidth: 1,
borderColor: '#FFFFFF',
width: mediaDimension,
height: mediaDimension,
},
textContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF',
},
noContentText: {
textAlign: 'center',
color: '#00536C',
},
});
const isMediaFile = ({ category }) => ['image', 'video', 'audio'].includes(category);
const isDocument = ({ category }) => category === 'document';
const renderMediaList = ({
title,
isFetching,
attachments,
onAttachmentOpen,
}) => (
<>
<Text style={[styles.text, styles.containerHeader]}>{title}</Text>
<FlatList
data={attachments}
numColumns={3}
keyExtractor={item => item.id}
renderItem={({ item: attachment }) => (
<TouchableOpacity onPress={() => onAttachmentOpen(attachment)}>
<Media
attachment={attachment}
isFetching={isFetching}
style={styles.mediaFile}
/>
</TouchableOpacity>
)}
/>
</>
);
renderMediaList.propTypes = {
title: PropTypes.string.isRequired,
isFetching: PropTypes.bool.isRequired,
attachments: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
onAttachmentOpen: PropTypes.func.isRequired,
};
const renderDocumentList = ({
locale,
title,
attachments,
onAttachmentOpen,
}) => (
<>
<Text style={[styles.text, styles.containerHeader]}>{title}</Text>
<FlatList
data={attachments}
keyExtractor={item => item.id}
renderItem={({ item: attachment }) => (
<Document
attachment={attachment}
locale={locale}
onPress={() => onAttachmentOpen(attachment)}
/>
)}
/>
</>
);
renderDocumentList.propTypes = {
locale: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
attachments: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
onAttachmentOpen: PropTypes.func.isRequired,
};
class SharedFileList extends Component {
constructor(props) {
super(props);
this.state = {
mediaFiles: [],
documents: [],
isFetching: false,
};
this.handleOpenAttachment = this.handleOpenAttachment.bind(this);
}
async componentDidMount() {
this.setState({ isFetching: true });
const { locale, messages } = this.props;
const attachments = await getDownloadedAttachments(messages);
const mediaFiles = getFilesWithTimeLine({ locale, files: attachments.filter(isMediaFile) });
const documents = getFilesWithTimeLine({ locale, files: attachments.filter(isDocument) });
this.setState({
mediaFiles,
documents,
isFetching: false,
});
}
async handleOpenAttachment(attachment) {
const { locale, handlePlayClicker } = this.props;
const { user, createdDate: createdAt } = attachment;
handlePlayClicker();
await navigateToAttachment({
locale,
attachment,
headerDetails: { createdAt, user },
});
}
render() {
const { locale } = this.props;
const { mediaFiles, documents, isFetching } = this.state;
const mediaFileCount = flatten(Object.values(mediaFiles)).length;
const documentFileCount = flatten(Object.values(documents)).length;
return (
<Container>
{isFetching ? (
<View style={styles.view}>
<ActivityIndicator color="#039BE5" size="large" />
</View>
) : (
<Tabs tabBarUnderlineStyle={styles.tabBarUnderline}>
<Tab
heading={`${translateString(locale)('Media')} (${mediaFileCount})`}
tabStyle={styles.tab}
textStyle={styles.text}
activeTabStyle={styles.activeTab}
activeTextStyle={styles.text}
>
{mediaFileCount ? (
<SectionList
sections={Object.values(mediaFiles).map((attachments, index) => {
const title = Object.keys(mediaFiles)[index];
const customKey = `media-files-${title.toLowerCase()}`;
return {
key: customKey,
data: [{ id: customKey }],
keyExtractor: ({ id }) => id,
renderItem: () => renderMediaList({
title,
attachments,
isFetching,
onAttachmentOpen: this.handleOpenAttachment,
}),
};
})}
contentContainerStyle={styles.mediaContainer}
/>
) : (
<View style={styles.textContainer}>
<H2 style={styles.noContentText}>No shared media...</H2>
</View>
)}
</Tab>
<Tab
heading={`${translateString(locale)('Documents')} (${documentFileCount})`}
tabStyle={styles.tab}
textStyle={styles.text}
activeTabStyle={styles.activeTab}
activeTextStyle={styles.text}
>
{documentFileCount ? (
<SectionList
sections={Object.values(documents).map((attachments, index) => {
const title = Object.keys(documents)[index];
const customKey = `documents-${title.toLowerCase()}`;
return {
key: customKey,
data: [{ id: customKey }],
keyExtractor: ({ id }) => id,
renderItem: () => renderDocumentList({
title,
locale,
attachments,
onAttachmentOpen: this.handleOpenAttachment,
}),
};
})}
contentContainerStyle={styles.documentContainer}
/>
) : (
<View style={styles.textContainer}>
<H2 style={styles.noContentText}>No shared document...</H2>
</View>
)}
</Tab>
</Tabs>
)}
</Container>
);
}
}
SharedFileList.propTypes = {
locale: PropTypes.string.isRequired,
messages: PropTypes.arrayOf(PropTypes.shape({})),
handlePlayClicker: PropTypes.func.isRequired,
};
SharedFileList.defaultProps = {
messages: [],
};
const mapStateToProps = ({ locale, currentConversation, messages }) => ({
locale,
messages: messages[currentConversation.id],
});
export { SharedFileList as UnconnectedSharedFileList };
export default connect(mapStateToProps, { handlePlayClicker: playClicker })(SharedFileList);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment