diff --git a/src/ts/components/Sponsor/store/index.ts b/src/ts/components/Sponsor/store/index.ts index 7dc2dcb..523de82 100644 --- a/src/ts/components/Sponsor/store/index.ts +++ b/src/ts/components/Sponsor/store/index.ts @@ -29,10 +29,11 @@ class SponsorStore { const ONE_MINUTE = 60 * 1000; setInterval(() => { if (this.type) return; - this.type = Math.random() > 0.5 - ? MODAL_TYPE.MONEY - : MODAL_TYPE.SHARE; - }, 10 * ONE_MINUTE); + this.type = MODAL_TYPE.SHARE; + // Math.random() > 0.5 + // ? MODAL_TYPE.MONEY + // : MODAL_TYPE.SHARE; + }, 7 * ONE_MINUTE); } open() { diff --git a/src/ts/pages/Team/components/Country/components/Charts.tsx b/src/ts/pages/Team/components/Country/components/Charts.tsx index d41f4b6..c3f9831 100644 --- a/src/ts/pages/Team/components/Country/components/Charts.tsx +++ b/src/ts/pages/Team/components/Country/components/Charts.tsx @@ -1,7 +1,4 @@ import React from 'react'; -import { observer } from 'mobx-react-lite'; - -import dataGripStore from 'ts/store/DataGrip'; import PageWrapper from 'ts/components/Page/wrapper'; import getOptions from 'ts/components/LineChart/helpers/getOptions'; @@ -25,18 +22,23 @@ function getTimeZoneChart(authors: any[]) { increment(acc, author.lastCommit.timezone.replace(':', '.')); return acc; }, {}); + const options = getOptions({ order: Object.keys(details).sort(), limit: 5, suffix: 'page.team.country.chart.item', }); + return [options, details]; } -const PieCharts = observer((): React.ReactElement | null => { - const authors = dataGripStore.dataGrip.author.statistic; - const rows = dataGripStore.dataGrip.country.statistic; - const [countryOptions, countryDetails] = getCountryChart(rows); +interface PieChartsProps { + authors: any[]; + countries: any[]; +} + +function PieCharts({ authors, countries }: PieChartsProps): React.ReactElement | null { + const [countryOptions, countryDetails] = getCountryChart(countries); const [timezoneOptions, timezoneDetails] = getTimeZoneChart(authors); return ( @@ -57,6 +59,6 @@ const PieCharts = observer((): React.ReactElement | null => { ); -}); +} export default PieCharts; diff --git a/src/ts/pages/Team/components/Country/components/Filters.tsx b/src/ts/pages/Team/components/Country/components/Filters.tsx new file mode 100644 index 0000000..cf82cee --- /dev/null +++ b/src/ts/pages/Team/components/Country/components/Filters.tsx @@ -0,0 +1,68 @@ +import React, { useMemo } from 'react'; +import { observer } from 'mobx-react-lite'; + +import dataGripStore from 'ts/store/DataGrip'; + +import SelectWithButtons from 'ts/components/UiKit/components/SelectWithButtons'; +import UiKitCheckbox from 'ts/components/UiKit/components/Checkbox'; +import Title from 'ts/components/Title'; + +import IFilters from '../interfaces/Filters'; +import { getOptions } from '../helpers'; + +import style from '../styles/index.module.scss'; + +interface FiltersProps { + filters: IFilters, + onChange: Function; +} + +const Filters = observer(({ + filters, + onChange, +}: FiltersProps) => { + const companies = dataGripStore.dataGrip.company.statistic; + const companyOptions = useMemo(() => getOptions(companies), companies); + const update = (property: string, value: any) => { + onChange({ + ...filters, + [property]: value, + hash: Math.random(), + }); + }; + + return ( + <> + + <div className={style.team_country_filter}> + <SelectWithButtons + title="page.team.tree.filters.author" + className={style.team_country_filter_select} + value={filters.company} + options={companyOptions} + onChange={(company: string) => update('company', company)} + /> + <UiKitCheckbox + title="page.team.country.filters.active" + className={style.team_country_filter_checkbox} + value={filters.isActive} + onChange={() => update('isActive', !filters.isActive)} + /> + <UiKitCheckbox + title="page.team.country.filters.dismissed" + className={style.team_country_filter_checkbox} + value={filters.isDismissed} + onChange={() => update('isDismissed', !filters.isDismissed)} + /> + <UiKitCheckbox + title="page.team.country.filters.staff" + className={style.team_country_filter_checkbox} + value={filters.isStaff} + onChange={() => update('isStaff', !filters.isStaff)} + /> + </div> + </> + ); +}); + +export default Filters; diff --git a/src/ts/pages/Team/components/Country/components/Map.tsx b/src/ts/pages/Team/components/Country/components/Map.tsx index 6c031b2..48d400d 100644 --- a/src/ts/pages/Team/components/Country/components/Map.tsx +++ b/src/ts/pages/Team/components/Country/components/Map.tsx @@ -1,77 +1,20 @@ -import React, { useMemo, useState } from 'react'; -import { observer } from 'mobx-react-lite'; +import React from 'react'; -import dataGripStore from 'ts/store/DataGrip'; - -import SelectWithButtons from 'ts/components/UiKit/components/SelectWithButtons'; -import UiKitCheckbox from 'ts/components/UiKit/components/Checkbox'; import TimeZoneMap from 'ts/components/TimeZoneMap'; import PageWrapper from 'ts/components/Page/Box'; import Title from 'ts/components/Title'; -import { t } from 'ts/helpers/Localization'; -import style from '../../../styles/country.module.scss'; - -function getOptions(companies: any[]) { - const options = companies.map((item: any) => ({ id: item.company, title: item.company })); - return [ - { id: '', title: t('page.common.filter.allUsers') }, - { id: Math.random(), title: 'Unknown' }, - ...options, - ]; +interface CustomMapProps { + authors: any[]; } -const CustomMap = observer(() => { - const companies = dataGripStore.dataGrip.company.statistic; - const companyOptions = useMemo(() => getOptions(companies), companies); - - const [company, setCompany] = useState<string>(''); - const [isStaff, setIsStaff] = useState<boolean>(true); - const [isActive, setIsActive] = useState<boolean>(true); - const [isDismissed, setIsDismissed] = useState<boolean>(true); - - const authors = dataGripStore.dataGrip.author.statistic - .filter((author: any) => { - if (company && author.lastCompany !== company) return false; - if (!isStaff && author.isStaff) return false; - if (!isActive && !author.isDismissed && !author.isStaff) return false; - if (!isDismissed && author.isDismissed && !author.isStaff) return false; - return true; - }); - +function CustomMap({ authors }: CustomMapProps) { return ( <PageWrapper> <Title title="page.team.country.byTimezone"/> <TimeZoneMap authors={authors}/> - <div className={style.team_country_filter}> - <UiKitCheckbox - title="page.team.country.filters.active" - className={style.team_country_filter_checkbox} - value={isActive} - onChange={() => setIsActive(!isActive)} - /> - <UiKitCheckbox - title="page.team.country.filters.dismissed" - className={style.team_country_filter_checkbox} - value={isDismissed} - onChange={() => setIsDismissed(!isDismissed)} - /> - <UiKitCheckbox - title="page.team.country.filters.staff" - className={style.team_country_filter_checkbox} - value={isStaff} - onChange={() => setIsStaff(!isStaff)} - /> - <SelectWithButtons - title="page.team.tree.filters.author" - className={style.team_country_filter_select} - value={company} - options={companyOptions} - onChange={(id: string) => setCompany(id)} - /> - </div> </PageWrapper> ); -}); +} export default CustomMap; diff --git a/src/ts/pages/Team/components/Country/helpers/index.ts b/src/ts/pages/Team/components/Country/helpers/index.ts new file mode 100644 index 0000000..6363987 --- /dev/null +++ b/src/ts/pages/Team/components/Country/helpers/index.ts @@ -0,0 +1,48 @@ +import { t } from 'ts/helpers/Localization'; + +import IFilters from '../interfaces/Filters'; + +export function getOptions(companies: any[]) { + const options = companies.map((item: any) => ({ id: item.company, title: item.company })); + return [ + { id: '', title: t('page.common.filter.allUsers') }, + { id: Math.random(), title: 'Unknown' }, + ...options, + ]; +} + +export function getDefaultFilters(): IFilters { + return { + hash: Math.random(), + isActive: true, + isDismissed: true, + isStaff: true, + company: '', + }; +} + +export function getFilterForAuthors(filters: IFilters) { + return (author: any) => { + if (filters.company && author.lastCompany !== filters.company) return false; + if (!filters.isStaff && author.isStaff) return false; + if (!filters.isActive && !author.isDismissed && !author.isStaff) return false; + if (!filters.isDismissed && author.isDismissed && !author.isStaff) return false; + return true; + }; +} + +export function getCountryByAuthors(authors: any[]) { + const isCorrectAuthor = authors.reduce((acc: any, item: any) => { + acc.set(item.author, true); + return acc; + }, new Map()); + + return (item: any) => { + const employments = item.employments + .filter((name: string) => isCorrectAuthor.has(name)); + + return employments.length + ? ({ ...item, employments }) + : null; + }; +} diff --git a/src/ts/pages/Team/components/Country/index.tsx b/src/ts/pages/Team/components/Country/index.tsx index 044c944..74f695d 100644 --- a/src/ts/pages/Team/components/Country/index.tsx +++ b/src/ts/pages/Team/components/Country/index.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo, useState } from 'react'; import { observer } from 'mobx-react-lite'; import ISort from 'ts/interfaces/Sort'; @@ -15,28 +15,56 @@ import Countries from './components/Countries'; import CountryCharts from './components/Charts'; import fullScreen from 'ts/store/FullScreen'; -import CustomMap from './components/Map'; +import IFilters from './interfaces/Filters'; +import Filters from './components/Filters'; import Travel from './components/Travel'; +import CustomMap from './components/Map'; + +import { getCountryByAuthors, getDefaultFilters, getFilterForAuthors } from './helpers'; const Country = observer(({ mode, }: ICommonPageProps): React.ReactElement | null => { - const authors = dataGripStore.dataGrip.author.statistic; - const countryRows = dataGripStore.dataGrip.country.statistic; - const travel = authors.filter((dot: any) => dot?.country?.length) - .sort((a: any, b: any) => b?.country?.length - a?.country?.length); + const [filters, setFilters] = useState<IFilters>(getDefaultFilters()); + + const dataGripAuthors = dataGripStore.dataGrip.author.statistic; + const authors = useMemo(() => ( + dataGripAuthors.filter(getFilterForAuthors(filters)) + ), [dataGripAuthors, filters.hash]); + + const dataGripCountries = dataGripStore.dataGrip.country.statistic; + const countries = useMemo(() => ( + dataGripCountries.map(getCountryByAuthors(authors)).filter((v: any) => v) + ), [dataGripCountries, filters.hash]); + + const travel = useMemo(() => ( + authors + .filter((dot: any) => dot?.country?.length) + .sort((a: any, b: any) => b?.country?.length - a?.country?.length) + ), [authors, filters.hash]); const canShowByCountries = (!fullScreen.isOpen || fullScreen.mode === 'countries'); const canShowByTravel = (!fullScreen.isOpen || fullScreen.mode === 'travel') && travel.length; - if (!countryRows?.length) { + if (!countries?.length) { return mode !== 'print' ? (<NothingFound/>) : null; } return ( <> - {!fullScreen.isOpen && <CustomMap />} - {!fullScreen.isOpen && <CountryCharts />} + {!fullScreen.isOpen && ( + <> + <Filters + filters={filters} + onChange={setFilters} + /> + <CustomMap authors={authors} /> + <CountryCharts + authors={authors} + countries={countries} + /> + </> + )} {canShowByCountries ? ( <> @@ -44,13 +72,13 @@ const Country = observer(({ <DataLoader to="response" loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({ - content: countryRows, pagination, sort, mode, + content: countries, pagination, sort, mode, })} - watch={`${mode}${dataGripStore.hash}`} + watch={`${mode}${dataGripStore.hash}${filters.hash}`} > <Countries mode={mode} - rowsForExcel={countryRows} + rowsForExcel={countries} /> <Pagination/> </DataLoader> @@ -65,11 +93,11 @@ const Country = observer(({ loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({ content: travel, pagination, sort, mode, })} - watch={`${mode}${dataGripStore.hash}`} + watch={`${mode}${dataGripStore.hash}${filters.hash}`} > <Travel mode={mode} - rowsForExcel={countryRows} + rowsForExcel={countries} /> <Pagination/> </DataLoader> diff --git a/src/ts/pages/Team/components/Country/interfaces/Filters.ts b/src/ts/pages/Team/components/Country/interfaces/Filters.ts new file mode 100644 index 0000000..2702bd2 --- /dev/null +++ b/src/ts/pages/Team/components/Country/interfaces/Filters.ts @@ -0,0 +1,10 @@ +interface IFilters { + company: string; + isStaff: boolean; + isActive: boolean; + isDismissed: boolean; + + hash: number; +} + +export default IFilters; diff --git a/src/ts/pages/Team/components/Country/styles/index.module.scss b/src/ts/pages/Team/components/Country/styles/index.module.scss new file mode 100644 index 0000000..0d1da94 --- /dev/null +++ b/src/ts/pages/Team/components/Country/styles/index.module.scss @@ -0,0 +1,16 @@ +@import 'src/styles/variables'; + +.team_country_filter { + margin: 0 0 var(--space-xxl); + + &_checkbox, + &_select { + display: inline-block; + margin-right: var(--space-xxl); + vertical-align: middle; + } + + &_select { + min-width: 350px; + } +} diff --git a/src/ts/translations/de/pages.ts b/src/ts/translations/de/pages.ts index c2f31d0..6a1c8a5 100644 --- a/src/ts/translations/de/pages.ts +++ b/src/ts/translations/de/pages.ts @@ -287,7 +287,7 @@ will be marked as a jump in "deleted" and "added" lines. § page.person.week.workDay: weekdays § page.person.week.weekends: weekends § page.sponsor.title: Please, support this project -§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. +§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ]. § page.sponsor.share.button: Copy the link § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.qr: One-time payment (only Russia) diff --git a/src/ts/translations/en/pages.ts b/src/ts/translations/en/pages.ts index b55d2e7..897aab5 100644 --- a/src/ts/translations/en/pages.ts +++ b/src/ts/translations/en/pages.ts @@ -289,7 +289,7 @@ will be marked as a jump in "deleted" and "added" lines. § page.person.week.workDay: weekdays § page.person.week.weekends: weekends § page.sponsor.title: Please, support this project -§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. +§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ]. § page.sponsor.share.button: Copy the link § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.qr: One-time payment (only Russia) diff --git a/src/ts/translations/es/pages.ts b/src/ts/translations/es/pages.ts index d308de1..7eb5ca7 100644 --- a/src/ts/translations/es/pages.ts +++ b/src/ts/translations/es/pages.ts @@ -287,7 +287,7 @@ git puede Mostrar una pequeña cantidad de cambios en las estadísticas, y el re § page.person.week.workDay: entresemana § page.person.week.weekends: día de descanso § page.sponsor.title: Please, support this project -§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. +§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ]. § page.sponsor.share.button: Copy the link § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.qr: One-time payment (only Russia) diff --git a/src/ts/translations/fr/pages.ts b/src/ts/translations/fr/pages.ts index 492b925..c18de23 100644 --- a/src/ts/translations/fr/pages.ts +++ b/src/ts/translations/fr/pages.ts @@ -286,7 +286,7 @@ export default ` § page.person.week.workDay: jours de semaine § page.person.week.weekends: congés § page.sponsor.title: Please, support this project -§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. +§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ]. § page.sponsor.share.button: Copy the link § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.qr: One-time payment (only Russia) diff --git a/src/ts/translations/ja/pages.ts b/src/ts/translations/ja/pages.ts index b55d2e7..897aab5 100644 --- a/src/ts/translations/ja/pages.ts +++ b/src/ts/translations/ja/pages.ts @@ -289,7 +289,7 @@ will be marked as a jump in "deleted" and "added" lines. § page.person.week.workDay: weekdays § page.person.week.weekends: weekends § page.sponsor.title: Please, support this project -§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. +§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ]. § page.sponsor.share.button: Copy the link § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.qr: One-time payment (only Russia) diff --git a/src/ts/translations/pt/pages.ts b/src/ts/translations/pt/pages.ts index b55d2e7..897aab5 100644 --- a/src/ts/translations/pt/pages.ts +++ b/src/ts/translations/pt/pages.ts @@ -289,7 +289,7 @@ will be marked as a jump in "deleted" and "added" lines. § page.person.week.workDay: weekdays § page.person.week.weekends: weekends § page.sponsor.title: Please, support this project -§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. +§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ]. § page.sponsor.share.button: Copy the link § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.qr: One-time payment (only Russia) diff --git a/src/ts/translations/ru/pages.ts b/src/ts/translations/ru/pages.ts index 9dd7c6c..314978b 100644 --- a/src/ts/translations/ru/pages.ts +++ b/src/ts/translations/ru/pages.ts @@ -289,7 +289,7 @@ git может показать малое количество изменени § page.person.week.workDay: будни § page.person.week.weekends: выходные § page.sponsor.title: Поддержите проект -§ page.sponsor.share.description: Расскажите о нашем [проекте|https://github.com/bakhirev/assayo] в соцсетях! Можно поделиться [статьей|https://habr.com/ru/articles/763342/], [постом|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] или сделать видео-обзор. +§ page.sponsor.share.description: Расскажите о нашем [проекте|https://github.com/bakhirev/assayo] в соцсетях! Можно поделиться [статьей|https://habr.com/ru/articles/763342/], [постом|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] или [видео|https://www.youtube.com/watch?v=jwCp_-bhrCQ]. § page.sponsor.share.button: Копировать ссылку § page.sponsor.money.description: Мы будем рады, если вы поддержите нас любой суммой! Все средства пойдут на дальнейшее развитие проекта. § page.sponsor.money.qr: Разовый платёж (СБП)