catarse/catarse.js

View on GitHub
legacy/src/root/projects-explore.ts

Summary

Maintainability
C
1 day
Test Coverage
/**
 * window.root.ProjectsExplore component
 * A root component to show projects according to user defined filters
 *
 * Example:
 * To mount this component just create a DOM element like:
 * <div data-mithril="ProjectsExplore">
 */
import m from 'mithril';
import _ from 'underscore';
import h from '../h';
import UnsignedFriendFacebookConnect from '../c/unsigned-friend-facebook-connect';
import { CityState } from '../@types/city-state'
import { Category, Filter, ProjectsExploreViewModel, ProjectsExploreVMSearchParams } from '../vms/projects-explore-vm';
import { ExploreSearchFilterSelect } from '../c/explore/explore-search-filter-select';
import { ExploreFilterSelect } from '../c/explore/explore-filter-select';
import { ExploreProjectsFoundCounter } from '../c/explore/explore-projects-found-counter';
import { ExploreProjectsList } from '../c/explore/explore-projects-list';
import { ProjectsExplorerFooter } from '../c/projects-explore-footer';
import { ProjectsExploreLoadMoreButton } from '../c/projects-explore-load-more-button';
import { defineDeepObject } from '../utils/deep-object-operators';
import { ExploreSearchParam } from '../c/explore/explore-search-param';
import { ThisWindow } from '../@types/window';
import ExploreMobileSearch from '../c/explore/explore-mobile-search';

declare var window : ThisWindow

type ProjectExploreAttrs = {
    pg_search?: string
    mode?: string
    category_id?: number
    city_name?: string
    state_acronym?: string
    state_name?: string
    filter?: string
}

type ProjectExploreState = {
    projectsExploreVM: ProjectsExploreViewModel
    hasFBAuth: boolean
    hasSpecialFooter(category_id : number): boolean
    externalLinkCategories: {
        [category_id:number] : {
            icon: string
            title: string
            link: string
            cta: string
        }
    }
}

const I18nScope = _.partial(h.i18nScope, 'pages.explore');

const projectsExplore : m.Component<ProjectExploreAttrs, ProjectExploreState> = {

    oninit(vnode) {
        
        h.scrollTop();
        const currentUser = h.getUser() || {};
        const hasFBAuth = currentUser.has_fb_auth;
        const externalLinkCategories = window.I18n.translations[window.I18n.currentLocale()].projects.index.explore_categories;
        const hasSpecialFooter = categoryId => !_.isUndefined(externalLinkCategories[categoryId]);
        const projectsExploreVM = new ProjectsExploreViewModel(getProjectsViewQuery());

        window.addEventListener('popstate', () => {
            projectsExploreVM.search(getProjectsViewQuery());
        });

        window.addEventListener('pushstate', () => {
            projectsExploreVM.search(getProjectsViewQuery());
        });

        projectsExploreVM.subscribe({
            next(query) {
                
                h.scrollTop();

                const removeQueryParams = [
                    'mode',
                    'category_id',
                    'state_acronym',
                    'state_name',
                    'city_name',
                    'filter',
                ];
                
                h.setAndResetMultParamsArray(query, removeQueryParams);
            }
        });

        function getProjectsViewQuery() {
            const searchParam = h.paramByName('pg_search') || vnode.attrs.pg_search;
            const mode = h.paramByName('mode') || vnode.attrs.mode || 'all_modes';
            const filter = h.paramByName('filter') || vnode.attrs.filter || 'projects_we_love';
            const category_id = Number(h.paramByName('category_id')) || vnode.attrs.category_id || null;
            const cityState = getCityStateFromSearchParams();
    
            return {
                searchParam,
                mode,
                category_id,
                cityState: _.isEmpty(cityState) ? null : cityState,
                filter: mode === 'sub' ? 'all' : filter
            } as ProjectsExploreVMSearchParams;
        }

        function getCityStateFromSearchParams() : CityState {
            const city_name = h.paramByName('city_name') || vnode.attrs.city_name;
            const state_acronym = h.paramByName('state_acronym') || vnode.attrs.state_acronym;
            const state_name = h.paramByName('state_name') || vnode.attrs.state_name;

            const cityState = defineDeepObject('city.name', city_name);
            defineDeepObject('state.acronym', state_acronym, cityState);
            defineDeepObject('state.state_name', state_name, cityState);
            return cityState as CityState;
        };

        vnode.state = {
            projectsExploreVM,
            hasFBAuth,
            hasSpecialFooter,
            externalLinkCategories,
        };
    },
    onremove() {
        window.removeEventListener('popstate', window.onpopstate);
        window.removeEventListener('pushstate', window.onpushstate);
    },
    view({state, attrs}) {
        
        const projectsExploreVM : ProjectsExploreViewModel = state.projectsExploreVM;
        const projectsCollection = projectsExploreVM.projectsView.collection();
        const isContributedByFriendsFilter = projectsExploreVM.filter === 'contributed_by_friends';
        const hasSpecialFooter = state.hasSpecialFooter(projectsExploreVM.category_id);
        const showProjectsFoundCounter = !projectsExploreVM.projectsView.isLoading();
        const showConnectToFacebookButton = isContributedByFriendsFilter && _.isEmpty(projectsCollection) && !state.hasFBAuth;
        const showNextPageButton = !projectsExploreVM.projectsView.isLastPage() && !projectsExploreVM.projectsView.isLoading() && !_.isEmpty(projectsCollection);
        const specialFooterData = state.externalLinkCategories[projectsExploreVM.category_id] || { icon: '', title: '', link: '', cta: ''};
        const searchParam = state.projectsExploreVM.searchParam
        const hasSeachParam = !_.isEmpty(searchParam)

        const modes = [
            {
                label: 'Todos os projetos',
                value: 'all_modes',
            },
            {
                label: 'Projetos pontuais',
                value: 'not_sub',
            },
            {
                label: 'Assinaturas',
                value: 'sub',
            },
            {
                label: 'Projetos COVID-19',
                value: 'covid_19',
            },                        
        ];

        return m('#explore', {
            oncreate: h.setPageTitle(window.I18n.t('header_html', I18nScope()))
        }, [
            m('.hero-search.explore', [
                m('.u-marginbottom-10.w-container', m(ExploreMobileSearch)),
                m('.u-text-center.w-container', [
                    [
                        hasSeachParam ?
                            [
                                m('div', [
                                    m('.explore-text-fixed', 'Busca por'),
                                    m(ExploreSearchParam, {
                                        mobileLabel: 'BUSCA',
                                        searchParam,
                                        onClose: () => m.route.set('/pt/explore?filter=all')
                                    })
                                ])
                            ]
                            :
                            [
                                m('div', [
                                    m('.explore-text-fixed', 'Quero ver'),
                                    m(ExploreFilterSelect, {
                                        values: modes,
                                        mobileLabel: 'MODALIDADE',
                                        selectedItem: () => ({ label: projectsExploreVM.modeName, value: projectsExploreVM.mode }), 
                                        itemToString: (item : {label : string, value : string}) => item.label,
                                        isSelected: (item : {label : string, value : string}) => item.value === projectsExploreVM.mode,
                                        onSelect: (item) => projectsExploreVM.mode = item.value,
                                    }),
                                    m('.explore-text-fixed', 'de'),
                                    m(ExploreFilterSelect, {
                                        values: projectsExploreVM.categories,
                                        mobileLabel: 'CATEGORIA',
                                        splitNumberColumns: 2,
                                        selectedItem: () => projectsExploreVM.category,
                                        itemToString: (category : Category) => category.name,
                                        isSelected: (category : Category) => projectsExploreVM.category_id === category.id,
                                        onSelect: (category : Category) => projectsExploreVM.category = category,
                                    }),
                                ]),
                                m('div', [
                                    m('div.explore-text-fixed', 'localizados em'),
                                    m(ExploreSearchFilterSelect, {
                                        onSearch: (inputText : string) => projectsExploreVM.searchLocations(inputText),
                                        onSelect: (cityState : CityState) => projectsExploreVM.cityState = cityState,
                                        selectedItem: () => projectsExploreVM.cityState,
                                        foundItems: () => projectsExploreVM.foundLocations,
                                        noneSelected: 'Brasil',
                                        mobileLabel: 'LOCAL',
                                        isLoading: () => projectsExploreVM.isLoadingLocationsSearch,
                                        itemToString: (cityState : CityState) => {
                                            const firstPart = `${cityState.city ? cityState.city.name : cityState.state.state_name}`;
                                            const secondPart = `${cityState.city ? `, ${cityState.state.acronym}` : ' (Estado)'}`;
                                            return `${firstPart}${secondPart}`;
                                        },
                                    }),
                                    [
                                        projectsExploreVM.mode !== 'sub' && 
                                        [
                                            m('.explore-text-fixed', 'que são'),
                                            m(ExploreFilterSelect, {
                                                values: projectsExploreVM.filters,
                                                mobileLabel: 'FILTRO',
                                                selectedItem: () => ({
                                                    nicename: projectsExploreVM.filterName,
                                                    keyName: projectsExploreVM.filter
                                                } as { nicename : string, keyName : string }),
                                                itemToString: (item : Filter) => item.nicename,
                                                isSelected: (item : Filter) => projectsExploreVM.filter === item.keyName,
                                                onSelect: (item : Filter) => projectsExploreVM.filter = item.keyName,
                                            }),
                                        ]
                                    ]
                                ])
                            ]
                    ]
                ])
            ]), 
            [
                showProjectsFoundCounter &&
                m(ExploreProjectsFoundCounter, {
                    total: projectsExploreVM.projectsView.total(),
                }, [
                    projectsExploreVM.cityState?.city &&
                    m('div.fontsize-small.fontcolor-secondary.fontweight-semibold', [
                        m('span.fas.fa-map-marker-check.text-success'),
                        ` ${projectsExploreVM.amountFoundOnLocation || 'Nenhum'} em ${projectsExploreVM.cityState.city.name}, ${projectsExploreVM.cityState.state.acronym}  `,
                        '|',
                        ` ${(projectsExploreVM.projectsView.total() - projectsExploreVM.amountFoundOnLocation) || 'Nenhum'} em outras cidades de ${projectsExploreVM.cityState.state.acronym}`
                    ])
                ])
            ],
            [
                showConnectToFacebookButton &&
                m(UnsignedFriendFacebookConnect)
            ],
            m(ExploreProjectsList, {
                projects: projectsExploreVM.projectsView,
                isSearch: projectsExploreVM.isTextSearch,
                filterKeyName: projectsExploreVM.filter,
            }),
            m(ProjectsExploreLoadMoreButton, {
                showNextPageButton,
                onclick(event : Event) {
                    projectsExploreVM.projectsView.nextPage();
                    return false;
                }
            }),
            m(ProjectsExplorerFooter, {
                hasSpecialFooter,
                ...specialFooterData
            })
        ]);
    }
};

export default projectsExplore;