@@ -19,6 +19,7 @@ import {
1919} from 'react-native' ;
2020
2121import DiscoverComponents from './DiscoverScreenComponents' ;
22+ import { PRIMARY_TAGS } from './DiscoverScreenComponents/TagSplash' ;
2223import { ThemeContext } from '../ThemeContext' ;
2324import Site from '../site' ;
2425import i18n from 'i18n-js' ;
@@ -114,6 +115,11 @@ class DiscoverScreen extends React.Component {
114115 hotTopicsPage : 1 ,
115116 hotTopicsHasMore : false ,
116117
118+ // All communities
119+ communitiesFilter : null , // null = all, 'recent' = order by latest, otherwise a tag
120+ allCommunities : [ ] ,
121+ allCommunitiesLoading : false ,
122+
117123 // Community detail
118124 activeCommunity : null ,
119125 communityTopics : [ ] ,
@@ -233,7 +239,11 @@ class DiscoverScreen extends React.Component {
233239 this . setState ( {
234240 view : VIEWS . ALL_COMMUNITIES ,
235241 previousView : VIEWS . SPLASH ,
242+ communitiesFilter : tag ,
243+ allCommunities : [ ] ,
244+ allCommunitiesLoading : true ,
236245 } ) ;
246+ this . _fetchAllCommunities ( tag ) ;
237247 }
238248 } )
239249 . catch ( e => {
@@ -534,10 +544,89 @@ class DiscoverScreen extends React.Component {
534544 }
535545
536546 _goToAllCommunities ( ) {
547+ const filter = this . state . activeTag ;
548+ if ( this . state . tagCommunitiesLoading ) {
549+ this . setState ( {
550+ view : VIEWS . ALL_COMMUNITIES ,
551+ previousView : VIEWS . TAG_DETAIL ,
552+ communitiesFilter : filter ,
553+ allCommunities : [ ] ,
554+ allCommunitiesLoading : true ,
555+ } ) ;
556+ this . _fetchAllCommunities ( filter ) ;
557+ } else {
558+ this . setState ( {
559+ view : VIEWS . ALL_COMMUNITIES ,
560+ previousView : VIEWS . TAG_DETAIL ,
561+ communitiesFilter : filter ,
562+ allCommunities : this . state . tagCommunities ,
563+ allCommunitiesLoading : false ,
564+ } ) ;
565+ }
566+ }
567+
568+ _goToAllCommunitiesFromSplash ( filter = null ) {
537569 this . setState ( {
538570 view : VIEWS . ALL_COMMUNITIES ,
539- previousView : VIEWS . TAG_DETAIL ,
571+ previousView : VIEWS . SPLASH ,
572+ communitiesFilter : filter ,
573+ allCommunities : [ ] ,
574+ allCommunitiesLoading : true ,
575+ } ) ;
576+ this . _fetchAllCommunities ( filter ) ;
577+ }
578+
579+ _selectFromTagDetail ( key ) {
580+ if ( key === null ) {
581+ this . _goToAllCommunitiesFromSplash ( null ) ;
582+ } else if ( key === 'recent' ) {
583+ this . _goToAllCommunitiesFromSplash ( 'recent' ) ;
584+ } else if ( key !== this . state . activeTag ) {
585+ this . onSelectTag ( key ) ;
586+ }
587+ }
588+
589+ _selectCommunitiesFilter ( filter ) {
590+ if ( filter === this . state . communitiesFilter ) {
591+ return ;
592+ }
593+ this . setState ( {
594+ communitiesFilter : filter ,
595+ allCommunities : [ ] ,
596+ allCommunitiesLoading : true ,
540597 } ) ;
598+ this . _fetchAllCommunities ( filter ) ;
599+ }
600+
601+ _fetchAllCommunities ( filter ) {
602+ let searchString ;
603+ if ( filter === 'recent' ) {
604+ searchString = '#discover order:latest_topic' ;
605+ } else if ( filter ) {
606+ searchString = `#discover #${ filter } order:featured` ;
607+ } else {
608+ searchString = '#discover order:featured' ;
609+ }
610+ const url = `${ this . baseUrl } ${ encodeURIComponent ( searchString ) } &page=1` ;
611+
612+ fetch ( url )
613+ . then ( res => res . json ( ) )
614+ . then ( json => {
615+ if ( filter !== this . state . communitiesFilter ) {
616+ return ; // stale response
617+ }
618+ this . setState ( {
619+ allCommunities : json . topics || [ ] ,
620+ allCommunitiesLoading : false ,
621+ } ) ;
622+ } )
623+ . catch ( e => {
624+ console . log ( e ) ;
625+ if ( filter !== this . state . communitiesFilter ) {
626+ return ;
627+ }
628+ this . setState ( { allCommunitiesLoading : false } ) ;
629+ } ) ;
541630 }
542631
543632 // ── Render ──
@@ -582,6 +671,8 @@ class DiscoverScreen extends React.Component {
582671 tags = { this . state . splashTags }
583672 loading = { this . state . splashTagsLoading }
584673 onSelectTag = { tag => this . onSelectTag ( tag ) }
674+ onSelectRecent = { ( ) => this . _goToAllCommunitiesFromSplash ( 'recent' ) }
675+ onSeeAllCommunities = { ( ) => this . _goToAllCommunitiesFromSplash ( ) }
585676 />
586677 </ View >
587678 ) ;
@@ -664,12 +755,12 @@ class DiscoverScreen extends React.Component {
664755
665756 _renderTagDetailView ( tabBarHeight ) {
666757 const theme = this . context ;
667- const tagLabel = this . _formatTagLabel ( this . state . activeTag ) ;
758+ const activeTagLabel = this . state . activeTag ;
668759
669760 const headerComponent = (
670761 < View >
671762 < Text style = { [ styles . sectionLabel , { color : theme . graySubtitle } ] } >
672- { i18n . t ( 'discover_communities_section' ) }
763+ { i18n . t ( 'discover_communities_section' , { tag : activeTagLabel } ) }
673764 </ Text >
674765 < DiscoverComponents . CommunityCarousel
675766 communities = { this . state . tagCommunities }
@@ -691,17 +782,17 @@ class DiscoverScreen extends React.Component {
691782 </ Text >
692783 </ TouchableHighlight >
693784 < Text style = { [ styles . sectionLabel , { color : theme . graySubtitle } ] } >
694- { i18n . t ( 'discover_topics_section' ) }
785+ { i18n . t ( 'discover_topics_section' , { tag : activeTagLabel } ) }
695786 </ Text >
696787 </ View >
697788 ) ;
698789
699790 return (
700791 < View style = { styles . container } >
701- < DiscoverComponents . TagDetailHeader
702- title = { tagLabel }
703- onBack = { ( ) => this . _navigateBack ( ) }
704- />
792+ { this . _renderSearchBox ( ) }
793+ { this . _renderCommunitiesTagBar ( this . state . activeTag , key =>
794+ this . _selectFromTagDetail ( key ) ,
795+ ) }
705796 < DiscoverComponents . DiscoverTopicList
706797 topics = { this . state . hotTopics }
707798 loading = { this . state . hotTopicsLoading }
@@ -723,26 +814,24 @@ class DiscoverScreen extends React.Component {
723814
724815 _renderAllCommunitiesView ( tabBarHeight ) {
725816 const theme = this . context ;
726- const tagLabel = this . _formatTagLabel ( this . state . activeTag ) ;
727- const title = `${ tagLabel } ${ i18n . t ( 'discover_communities' ) } ` ;
728817
729- const emptyComponent = this . state . tagCommunitiesLoading ? (
818+ const emptyComponent = this . state . allCommunitiesLoading ? (
730819 < View style = { styles . emptyResult } >
731820 < ActivityIndicator size = "large" color = { theme . grayUI } />
732821 </ View >
733822 ) : null ;
734823
735824 return (
736825 < View style = { styles . container } >
737- < DiscoverComponents . TagDetailHeader
738- title = { title }
739- onBack = { ( ) => this . _navigateBack ( ) }
740- />
826+ { this . _renderSearchBox ( ) }
827+ { this . _renderCommunitiesTagBar ( this . state . communitiesFilter , key =>
828+ this . _selectCommunitiesFilter ( key ) ,
829+ ) }
741830 < FlatList
742831 keyExtractor = { item => String ( item . id || item . featured_link ) }
743832 ListEmptyComponent = { emptyComponent }
744833 contentContainerStyle = { { paddingBottom : tabBarHeight } }
745- data = { this . state . tagCommunities }
834+ data = { this . state . allCommunities }
746835 renderItem = { ( { item } ) => this . _renderSiteItem ( { item } ) }
747836 extraData = { this . state . selectionCount }
748837 keyboardDismissMode = "on-drag"
@@ -751,6 +840,68 @@ class DiscoverScreen extends React.Component {
751840 ) ;
752841 }
753842
843+ _renderCommunitiesTagBar ( activeKey , onSelect ) {
844+ const theme = this . context ;
845+
846+ const primaryTagSet = new Set ( PRIMARY_TAGS . map ( t => t . tag ) ) ;
847+ const secondaryTags = ( this . state . splashTags || [ ] )
848+ . filter ( tag => ! primaryTagSet . has ( tag ) )
849+ . sort ( ( a , b ) => a . localeCompare ( b ) ) ;
850+
851+ const entries = [
852+ { key : null , label : i18n . t ( 'discover_all' ) } ,
853+ ...PRIMARY_TAGS . map ( ( { tag, label } ) => ( {
854+ key : tag ,
855+ label : label ,
856+ } ) ) ,
857+ { key : 'recent' , label : i18n . t ( 'discover_recent' ) } ,
858+ ...secondaryTags . map ( tag => ( {
859+ key : tag ,
860+ label : tag ,
861+ } ) ) ,
862+ ] ;
863+
864+ return (
865+ < ScrollView
866+ horizontal = { true }
867+ showsHorizontalScrollIndicator = { false }
868+ style = { styles . tagBar }
869+ contentContainerStyle = { styles . tagBarContent }
870+ keyboardShouldPersistTaps = "handled"
871+ >
872+ { entries . map ( entry => {
873+ const isSelected = entry . key === activeKey ;
874+ return (
875+ < TouchableHighlight
876+ key = { entry . key === null ? '__all__' : entry . key }
877+ accessibilityRole = "button"
878+ accessibilityLabel = { entry . label }
879+ style = { {
880+ ...styles . tagBarItem ,
881+ borderColor : theme . grayUILight ,
882+ backgroundColor : isSelected
883+ ? theme . grayBackground
884+ : theme . background ,
885+ } }
886+ underlayColor = { theme . grayBackground }
887+ onPress = { ( ) => onSelect ( entry . key ) }
888+ >
889+ < Text
890+ style = { {
891+ ...styles . tagBarItemText ,
892+ color : theme . tagButtonTextColor ,
893+ fontSize : this . state . largerUI ? 15 : 13 ,
894+ } }
895+ >
896+ { entry . label }
897+ </ Text >
898+ </ TouchableHighlight >
899+ ) ;
900+ } ) }
901+ </ ScrollView >
902+ ) ;
903+ }
904+
754905 _renderCommunityDetailView ( tabBarHeight ) {
755906 const community = this . state . activeCommunity ;
756907 if ( ! community ) {
@@ -772,6 +923,7 @@ class DiscoverScreen extends React.Component {
772923
773924 return (
774925 < View style = { styles . container } >
926+ { this . _renderSearchBox ( ) }
775927 < DiscoverComponents . TagDetailHeader
776928 title = { community . title }
777929 onBack = { ( ) => this . _navigateBack ( ) }
@@ -832,16 +984,6 @@ class DiscoverScreen extends React.Component {
832984 ) ;
833985 }
834986
835- _formatTagLabel ( tag ) {
836- if ( ! tag ) {
837- return '' ;
838- }
839- return tag
840- . split ( '-' )
841- . map ( word => word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) )
842- . join ( ' ' ) ;
843- }
844-
845987 // ── Pagination ──
846988
847989 _fetchNextSearchPage ( ) {
@@ -899,6 +1041,27 @@ const styles = StyleSheet.create({
8991041 paddingHorizontal : 16 ,
9001042 paddingTop : 16 ,
9011043 paddingBottom : 4 ,
1044+ textTransform : 'uppercase' ,
1045+ } ,
1046+ tagBar : {
1047+ flexGrow : 0 ,
1048+ flexShrink : 0 ,
1049+ paddingVertical : 8 ,
1050+ paddingHorizontal : 8 ,
1051+ } ,
1052+ tagBarContent : {
1053+ alignItems : 'center' ,
1054+ paddingRight : 16 ,
1055+ } ,
1056+ tagBarItem : {
1057+ paddingVertical : 8 ,
1058+ paddingHorizontal : 12 ,
1059+ borderRadius : 16 ,
1060+ borderWidth : StyleSheet . hairlineWidth ,
1061+ marginHorizontal : 4 ,
1062+ } ,
1063+ tagBarItemText : {
1064+ fontWeight : '500' ,
9021065 } ,
9031066 seeAllButton : {
9041067 marginHorizontal : 16 ,
0 commit comments