From fcc7adeed63c8dde8491a42e1533566743907dfe Mon Sep 17 00:00:00 2001 From: Peteranny Date: Tue, 27 Aug 2024 23:28:23 +0800 Subject: [PATCH 01/13] removes matches filter --- .../CompanyAndJobTitle/useSearchbar.js | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/components/CompanyAndJobTitle/useSearchbar.js b/src/components/CompanyAndJobTitle/useSearchbar.js index 5eff898af..c67ef55f3 100644 --- a/src/components/CompanyAndJobTitle/useSearchbar.js +++ b/src/components/CompanyAndJobTitle/useSearchbar.js @@ -106,7 +106,7 @@ Searchbar.propTypes = { }; const useSearchbar = ({ pageType, tabType }) => { - const [filter, setFilter] = useSearchTextFromQuery(); + const [, setFilter] = useSearchTextFromQuery(); const translatedPageType = pageTypeTranslation[pageType]; const translatedTabType = tabTypeTranslation[tabType]; @@ -126,29 +126,6 @@ const useSearchbar = ({ pageType, tabType }) => { const label = `搜尋${translatedSearchingPageType}:`; const placeholder = `搜該${translatedPageType}指定${translatedSearchingPageType}${translatedTabType}`; - const getSearchingValue = useCallback( - ({ company, job_title }) => { - switch (pageType) { - case pageTypes.COMPANY: - return job_title.name; - case pageTypes.JOB_TITLE: - return company.name; - default: - return null; - } - }, - [pageType], - ); - - const matchesFilter = useCallback( - data => { - const value = getSearchingValue(data); - if (!value) return false; - return value.toLowerCase().includes(filter.toLowerCase()); - }, - [filter, getSearchingValue], - ); - const WrappedSearchbar = useCallback( () => ( { return { Searchbar: WrappedSearchbar, - matchesFilter, }; }; From f30b4cb59ea50d2e354d295720e64785d19ee8ad Mon Sep 17 00:00:00 2001 From: Peteranny Date: Tue, 27 Aug 2024 23:30:21 +0800 Subject: [PATCH 02/13] wrapped search bar --- .../CompanyInterviewExperiencesProvider.js | 2 +- .../Company/CompanyTimeAndSalaryProvider.js | 2 +- .../Company/CompanyWorkExperiencesProvider.js | 2 +- .../InterviewExperiences.js | 10 ++----- .../{useSearchbar.js => Searchbar.js} | 28 +++++++++---------- .../TimeAndSalary/TimeAndSalary.js | 9 ++---- .../WorkExperiences/WorkExperiences.js | 10 ++----- .../JobTitleInterviewExperiencesProvider.js | 2 +- .../JobTitle/JobTitleTimeAndSalaryProvider.js | 2 +- .../JobTitleWorkExperiencesProvider.js | 2 +- 10 files changed, 27 insertions(+), 42 deletions(-) rename src/components/CompanyAndJobTitle/{useSearchbar.js => Searchbar.js} (90%) diff --git a/src/components/Company/CompanyInterviewExperiencesProvider.js b/src/components/Company/CompanyInterviewExperiencesProvider.js index af6d8678d..22c7ff86e 100644 --- a/src/components/Company/CompanyInterviewExperiencesProvider.js +++ b/src/components/Company/CompanyInterviewExperiencesProvider.js @@ -16,7 +16,7 @@ import { usePageName, pageNameSelector } from './usePageName'; import { searchTextFromQuerySelector, useSearchTextFromQuery, -} from 'components/CompanyAndJobTitle/useSearchbar'; +} from 'components/CompanyAndJobTitle/Searchbar'; import { pageFromQuerySelector } from 'selectors/routing/page'; const useInterviewExperiencesBox = pageName => { diff --git a/src/components/Company/CompanyTimeAndSalaryProvider.js b/src/components/Company/CompanyTimeAndSalaryProvider.js index 2e97abfb9..232bde1ae 100644 --- a/src/components/Company/CompanyTimeAndSalaryProvider.js +++ b/src/components/Company/CompanyTimeAndSalaryProvider.js @@ -18,7 +18,7 @@ import { pageFromQuerySelector } from 'selectors/routing/page'; import { searchTextFromQuerySelector, useSearchTextFromQuery, -} from 'components/CompanyAndJobTitle/useSearchbar'; +} from 'components/CompanyAndJobTitle/Searchbar'; const useTimeAndSalaryBox = pageName => { const selector = useCallback( diff --git a/src/components/Company/CompanyWorkExperiencesProvider.js b/src/components/Company/CompanyWorkExperiencesProvider.js index c8ad5306d..2168e6322 100644 --- a/src/components/Company/CompanyWorkExperiencesProvider.js +++ b/src/components/Company/CompanyWorkExperiencesProvider.js @@ -20,7 +20,7 @@ import { pageFromQuerySelector } from 'selectors/routing/page'; import { searchTextFromQuerySelector, useSearchTextFromQuery, -} from 'components/CompanyAndJobTitle/useSearchbar'; +} from 'components/CompanyAndJobTitle/Searchbar'; const useWorkExperiencesBox = pageName => { const selector = useCallback( diff --git a/src/components/CompanyAndJobTitle/InterviewExperiences/InterviewExperiences.js b/src/components/CompanyAndJobTitle/InterviewExperiences/InterviewExperiences.js index 05a96c7b5..10f6d12ed 100644 --- a/src/components/CompanyAndJobTitle/InterviewExperiences/InterviewExperiences.js +++ b/src/components/CompanyAndJobTitle/InterviewExperiences/InterviewExperiences.js @@ -8,7 +8,7 @@ import { Section } from 'common/base'; import EmptyView from '../EmptyView'; import ExperienceEntry from './ExperienceEntry'; -import useSearchbar from '../useSearchbar'; +import Searchbar from '../Searchbar'; import { useQuery } from 'hooks/routing'; const InterviewExperiences = ({ @@ -22,22 +22,18 @@ const InterviewExperiences = ({ canView, }) => { const queryParams = useQuery(); - const { Searchbar } = useSearchbar({ - pageType, - tabType, - }); if (data.length === 0) { return (
- +
); } return (
- + {data.map(d => ( { +const WrappedSearchbar = ({ pageType, tabType }) => { const [, setFilter] = useSearchTextFromQuery(); const translatedPageType = pageTypeTranslation[pageType]; @@ -126,21 +126,19 @@ const useSearchbar = ({ pageType, tabType }) => { const label = `搜尋${translatedSearchingPageType}:`; const placeholder = `搜該${translatedPageType}指定${translatedSearchingPageType}${translatedTabType}`; - const WrappedSearchbar = useCallback( - () => ( - - ), - [label, placeholder, setFilter, pageType], + return ( + ); +}; - return { - Searchbar: WrappedSearchbar, - }; +WrappedSearchbar.propTypes = { + pageType: PropTypes.string.isRequired, + tabType: PropTypes.string.isRequired, }; -export default useSearchbar; +export default WrappedSearchbar; diff --git a/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js b/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js index e537cdef6..17c0bf6d1 100644 --- a/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js +++ b/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js @@ -9,7 +9,7 @@ import EmptyView from '../EmptyView'; import WorkingHourBlock from './WorkingHourBlock'; import ViewLog from './ViewLog'; import OvertimeSection from './OvertimeSection'; -import useSearchbar from '../useSearchbar'; +import Searchbar from '../Searchbar'; import { useQuery } from 'hooks/routing'; const TimeAndSalary = ({ @@ -27,17 +27,12 @@ const TimeAndSalary = ({ fetchPermission(); }, [fetchPermission]); - const { Searchbar } = useSearchbar({ - pageType, - tabType, - }); - const queryParams = useQuery(); return (
- + {(salaryWorkTimes.length > 0 && ( { const queryParams = useQuery(); - const { Searchbar } = useSearchbar({ - pageType, - tabType, - }); if (data.length === 0) { return (
- +
); } return (
- + {data.map(d => ( { const selector = useCallback( diff --git a/src/components/JobTitle/JobTitleTimeAndSalaryProvider.js b/src/components/JobTitle/JobTitleTimeAndSalaryProvider.js index 1e78f0b88..81872dd1c 100644 --- a/src/components/JobTitle/JobTitleTimeAndSalaryProvider.js +++ b/src/components/JobTitle/JobTitleTimeAndSalaryProvider.js @@ -18,7 +18,7 @@ import { pageFromQuerySelector } from 'selectors/routing/page'; import { searchTextFromQuerySelector, useSearchTextFromQuery, -} from 'components/CompanyAndJobTitle/useSearchbar'; +} from 'components/CompanyAndJobTitle/Searchbar'; const useTimeAndSalaryBox = pageName => { const selector = useCallback( diff --git a/src/components/JobTitle/JobTitleWorkExperiencesProvider.js b/src/components/JobTitle/JobTitleWorkExperiencesProvider.js index 3bb6aea7e..90c434efa 100644 --- a/src/components/JobTitle/JobTitleWorkExperiencesProvider.js +++ b/src/components/JobTitle/JobTitleWorkExperiencesProvider.js @@ -17,7 +17,7 @@ import { pageFromQuerySelector } from 'selectors/routing/page'; import { searchTextFromQuerySelector, useSearchTextFromQuery, -} from 'components/CompanyAndJobTitle/useSearchbar'; +} from 'components/CompanyAndJobTitle/Searchbar'; const useWorkExperiencesBox = pageName => { const selector = useCallback( From 5bfa84309b165e755c3ca253e0da6801fbf8b225 Mon Sep 17 00:00:00 2001 From: Peteranny Date: Tue, 27 Aug 2024 23:36:26 +0800 Subject: [PATCH 03/13] move search bar out --- .../InterviewExperiences.js | 3 --- .../InterviewExperiences/index.js | 14 ++++++++------ .../TimeAndSalary/TimeAndSalary.js | 4 ---- .../CompanyAndJobTitle/TimeAndSalary/index.js | 18 +++++++++++------- .../WorkExperiences/WorkExperiences.js | 3 --- .../WorkExperiences/index.js | 14 ++++++++------ 6 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/components/CompanyAndJobTitle/InterviewExperiences/InterviewExperiences.js b/src/components/CompanyAndJobTitle/InterviewExperiences/InterviewExperiences.js index 10f6d12ed..4480250c0 100644 --- a/src/components/CompanyAndJobTitle/InterviewExperiences/InterviewExperiences.js +++ b/src/components/CompanyAndJobTitle/InterviewExperiences/InterviewExperiences.js @@ -8,7 +8,6 @@ import { Section } from 'common/base'; import EmptyView from '../EmptyView'; import ExperienceEntry from './ExperienceEntry'; -import Searchbar from '../Searchbar'; import { useQuery } from 'hooks/routing'; const InterviewExperiences = ({ @@ -26,14 +25,12 @@ const InterviewExperiences = ({ if (data.length === 0) { return (
-
); } return (
- {data.map(d => ( + + - - - {(salaryWorkTimes.length > 0 && ( + + + - -
); } return (
- {data.map(d => ( + + - Date: Wed, 28 Aug 2024 00:18:19 +0800 Subject: [PATCH 04/13] statistics api --- src/actions/company.js | 52 ++++++++++++++++++- src/actions/jobTitle.js | 50 +++++++++++++++++- src/apis/company.js | 7 +++ src/apis/jobTitle.js | 7 +++ .../Company/CompanyTimeAndSalaryProvider.js | 36 ++++++++++--- .../JobTitle/JobTitleTimeAndSalaryProvider.js | 40 +++++++++++--- src/graphql/company.js | 8 +++ src/graphql/jobTitle.js | 8 +++ src/reducers/companyIndex.js | 11 ++++ src/reducers/jobTitleIndex.js | 11 ++++ src/selectors/companyAndJobTitle.js | 14 +++++ 11 files changed, 227 insertions(+), 17 deletions(-) diff --git a/src/actions/company.js b/src/actions/company.js index 1943cce5b..1501ad67a 100644 --- a/src/actions/company.js +++ b/src/actions/company.js @@ -12,6 +12,7 @@ import { companyIndexesBoxSelectorAtPage, companyOverviewBoxSelectorByName, companyTimeAndSalaryBoxSelectorByName, + companyTimeAndSalaryStatisticsBoxSelectorByName, companyInterviewExperiencesBoxSelectorByName, companyWorkExperiencesBoxSelectorByName, } from 'selectors/companyAndJobTitle'; @@ -22,11 +23,14 @@ import { getCompanyInterviewExperiences, getCompanyWorkExperiences, queryCompaniesApi, + getCompanyTimeAndSalaryStatistics, } from 'apis/company'; export const SET_STATUS = '@@company/SET_STATUS'; export const SET_OVERVIEW = '@@COMPANY/SET_OVERVIEW'; export const SET_TIME_AND_SALARY = '@@COMPANY/SET_TIME_AND_SALARY'; +export const SET_TIME_AND_SALARY_STATISTICS = + '@@COMPANY/SET_TIME_AND_SALARY_STATISTICS'; export const SET_INTERVIEW_EXPERIENCES = '@@COMPANY/SET_INTERVIEW_EXPERIENCES'; export const SET_WORK_EXPERIENCES = '@@COMPANY/SET_WORK_EXPERIENCES'; export const SET_INDEX = '@@COMPANY/SET_INDEX'; @@ -207,7 +211,6 @@ export const queryCompanyTimeAndSalary = ({ limit, salary_work_times: data.salaryWorkTimesResult.salaryWorkTimes, salary_work_times_count: data.salaryWorkTimesResult.count, - salary_work_time_statistics: data.salary_work_time_statistics, }; dispatch(setTimeAndSalary(companyName, getFetched(timeAndSalaryData))); @@ -216,6 +219,53 @@ export const queryCompanyTimeAndSalary = ({ } }; +const setTimeAndSalaryStatistics = (companyName, box) => ({ + type: SET_TIME_AND_SALARY_STATISTICS, + companyName, + box, +}); + +export const queryCompanyTimeAndSalaryStatistics = ({ companyName }) => async ( + dispatch, + getState, +) => { + const box = companyTimeAndSalaryStatisticsBoxSelectorByName(companyName)( + getState(), + ); + if (isFetching(box) || (isFetched(box) && box.data.name === companyName)) { + return; + } + + dispatch(setTimeAndSalaryStatistics(companyName, toFetching())); + + try { + const data = await getCompanyTimeAndSalaryStatistics({ + companyName, + }); + + // Not found case + if (data == null) { + return dispatch( + setTimeAndSalaryStatistics(companyName, getFetched(data)), + ); + } + + const timeAndSalaryStatisticsData = { + name: data.name, + salary_work_time_statistics: data.salary_work_time_statistics, + }; + + dispatch( + setTimeAndSalaryStatistics( + companyName, + getFetched(timeAndSalaryStatisticsData), + ), + ); + } catch (error) { + dispatch(setTimeAndSalaryStatistics(companyName, getError(error))); + } +}; + export const queryCompanyInterviewExperiences = ({ companyName, jobTitle, diff --git a/src/actions/jobTitle.js b/src/actions/jobTitle.js index bc560069d..e33766ee3 100644 --- a/src/actions/jobTitle.js +++ b/src/actions/jobTitle.js @@ -12,6 +12,7 @@ import { jobTitleIndexesBoxSelectorAtPage, jobTitleOverviewBoxSelectorByName, jobTitleTimeAndSalaryBoxSelectorByName, + jobTitleTimeAndSalaryStatisticsBoxSelectorByName, jobTitleInterviewExperiencesBoxSelectorByName, jobTitleWorkExperiencesBoxSelectorByName, } from 'selectors/companyAndJobTitle'; @@ -19,6 +20,7 @@ import { getJobTitle as getJobTitleApi, queryJobTitleOverview as queryJobTitleOverviewApi, getJobTitleTimeAndSalary, + getJobTitleTimeAndSalaryStatistics, getJobTitleInterviewExperiences, getJobTitleWorkExperiences, queryJobTitlesApi, @@ -27,6 +29,8 @@ import { export const SET_STATUS = '@@JOB_TITLE/SET_STATUS'; export const SET_OVERVIEW = '@@JOB_TITLE/SET_OVERVIEW'; export const SET_TIME_AND_SALARY = '@@JOB_TITLE/SET_TIME_AND_SALARY'; +export const SET_TIME_AND_SALARY_STATISTICS = + '@@JOB_TITLE/SET_TIME_AND_SALARY_STATISTICS'; export const SET_INTERVIEW_EXPERIENCES = '@@JOB_TITLE/SET_INTERVIEW_EXPERIENCES'; export const SET_WORK_EXPERIENCES = '@@JOB_TITLE/SET_WORK_EXPERIENCES'; @@ -200,7 +204,6 @@ export const queryJobTitleTimeAndSalary = ({ limit, salary_work_times: data.salaryWorkTimesResult.salaryWorkTimes, salary_work_times_count: data.salaryWorkTimesResult.count, - salary_work_time_statistics: data.salary_work_time_statistics, }; dispatch(setTimeAndSalary(jobTitle, getFetched(timeAndSalaryData))); @@ -209,6 +212,51 @@ export const queryJobTitleTimeAndSalary = ({ } }; +const setTimeAndSalaryStatistics = (jobTitle, box) => ({ + type: SET_TIME_AND_SALARY_STATISTICS, + jobTitle, + box, +}); + +export const queryJobTitleTimeAndSalaryStatistics = ({ jobTitle }) => async ( + dispatch, + getState, +) => { + const box = jobTitleTimeAndSalaryStatisticsBoxSelectorByName(jobTitle)( + getState(), + ); + if (isFetching(box) || (isFetched(box) && box.data.name === jobTitle)) { + return; + } + + dispatch(setTimeAndSalaryStatistics(jobTitle, toFetching())); + + try { + const data = await getJobTitleTimeAndSalaryStatistics({ + jobTitle, + }); + + // Not found case + if (data == null) { + return dispatch(setTimeAndSalaryStatistics(jobTitle, getFetched(data))); + } + + const timeAndSalaryStatisticsData = { + name: data.name, + salary_work_time_statistics: data.salary_work_time_statistics, + }; + + dispatch( + setTimeAndSalaryStatistics( + jobTitle, + getFetched(timeAndSalaryStatisticsData), + ), + ); + } catch (error) { + dispatch(setTimeAndSalaryStatistics(jobTitle, getError(error))); + } +}; + const setInterviewExperiences = (jobTitle, box) => ({ type: SET_INTERVIEW_EXPERIENCES, jobTitle, diff --git a/src/apis/company.js b/src/apis/company.js index 48da0e270..15539a9b4 100644 --- a/src/apis/company.js +++ b/src/apis/company.js @@ -7,6 +7,7 @@ import { getCompanyInterviewExperiencesQuery, getCompanyWorkExperiencesQuery, queryCompaniesHavingDataGql, + getCompanyTimeAndSalaryStatisticsQuery, } from 'graphql/company'; // TODO: DEPRECATED @@ -43,6 +44,12 @@ export const getCompanyTimeAndSalary = ({ variables: { companyName, jobTitle, start, limit }, }).then(R.prop('company')); +export const getCompanyTimeAndSalaryStatistics = ({ companyName }) => + graphqlClient({ + query: getCompanyTimeAndSalaryStatisticsQuery, + variables: { companyName }, + }).then(R.prop('company')); + export const getCompanyInterviewExperiences = ({ companyName, jobTitle, diff --git a/src/apis/jobTitle.js b/src/apis/jobTitle.js index 57faf15f4..80604df32 100644 --- a/src/apis/jobTitle.js +++ b/src/apis/jobTitle.js @@ -7,6 +7,7 @@ import { getJobTitleTimeAndSalaryQuery, getJobTitleWorkExperiencesQuery, queryJobTitlesHavingDataGql, + getJobTitleTimeAndSalaryStatisticsQuery, } from 'graphql/jobTitle'; // TODO: DEPRECATED @@ -43,6 +44,12 @@ export const getJobTitleTimeAndSalary = ({ variables: { jobTitle, companyName, start, limit }, }).then(R.prop('job_title')); +export const getJobTitleTimeAndSalaryStatistics = ({ jobTitle }) => + graphqlClient({ + query: getJobTitleTimeAndSalaryStatisticsQuery, + variables: { jobTitle }, + }).then(R.prop('job_title')); + export const getJobTitleInterviewExperiences = ({ jobTitle, companyName, diff --git a/src/components/Company/CompanyTimeAndSalaryProvider.js b/src/components/Company/CompanyTimeAndSalaryProvider.js index 232bde1ae..e68b7c075 100644 --- a/src/components/Company/CompanyTimeAndSalaryProvider.js +++ b/src/components/Company/CompanyTimeAndSalaryProvider.js @@ -4,13 +4,17 @@ import TimeAndSalary from '../CompanyAndJobTitle/TimeAndSalary'; import usePermission from 'hooks/usePermission'; import { usePage } from 'hooks/routing/page'; import { tabType, pageType as PAGE_TYPE } from 'constants/companyJobTitle'; -import { queryCompanyTimeAndSalary } from 'actions/company'; +import { + queryCompanyTimeAndSalary, + queryCompanyTimeAndSalaryStatistics, +} from 'actions/company'; import { salaryWorkTimes as salaryWorkTimesSelector, salaryWorkTimesCount as salaryWorkTimesCountSelector, salaryWorkTimeStatistics as salaryWorkTimeStatisticsSelector, status as statusSelector, companyTimeAndSalaryBoxSelectorByName as timeAndSalaryBoxSelectorByName, + companyTimeAndSalaryStatisticsBoxSelectorByName as timeAndSalaryStatisticsBoxSelectorByName, } from 'selectors/companyAndJobTitle'; import { paramsSelector, querySelector } from 'common/routing/selectors'; import { usePageName, pageNameSelector } from './usePageName'; @@ -20,6 +24,17 @@ import { useSearchTextFromQuery, } from 'components/CompanyAndJobTitle/Searchbar'; +const useTimeAndSalaryStatisticsBox = pageName => { + const selector = useCallback( + state => { + const company = timeAndSalaryStatisticsBoxSelectorByName(pageName)(state); + return salaryWorkTimeStatisticsSelector(company); + }, + [pageName], + ); + return useSelector(selector); +}; + const useTimeAndSalaryBox = pageName => { const selector = useCallback( state => { @@ -48,6 +63,14 @@ const CompanyTimeAndSalaryProvider = () => { const start = (page - 1) * PAGE_SIZE; const limit = PAGE_SIZE; + useEffect(() => { + dispatch( + queryCompanyTimeAndSalaryStatistics({ + companyName: pageName, + }), + ); + }, [dispatch, pageName]); + useEffect(() => { dispatch( queryCompanyTimeAndSalary({ @@ -64,12 +87,11 @@ const CompanyTimeAndSalaryProvider = () => { fetchPermission(); }, [pageType, pageName, fetchPermission]); - const { - status, - salaryWorkTimes, - salaryWorkTimesCount, - salaryWorkTimeStatistics, - } = useTimeAndSalaryBox(pageName); + const salaryWorkTimeStatistics = useTimeAndSalaryStatisticsBox(pageName); + + const { status, salaryWorkTimes, salaryWorkTimesCount } = useTimeAndSalaryBox( + pageName, + ); return ( { + const selector = useCallback( + state => { + const jobTitle = timeAndSalaryStatisticsBoxSelectorByName(pageName)( + state, + ); + return salaryWorkTimeStatisticsSelector(jobTitle); + }, + [pageName], + ); + + return useSelector(selector); +}; + const useTimeAndSalaryBox = pageName => { const selector = useCallback( state => { @@ -28,7 +46,6 @@ const useTimeAndSalaryBox = pageName => { status: statusSelector(jobTitle), salaryWorkTimes: salaryWorkTimesSelector(jobTitle), salaryWorkTimesCount: salaryWorkTimesCountSelector(jobTitle), - salaryWorkTimeStatistics: salaryWorkTimeStatisticsSelector(jobTitle), }; }, [pageName], @@ -48,6 +65,14 @@ const JobTitleTimeAndSalaryProvider = () => { const start = (page - 1) * PAGE_SIZE; const limit = PAGE_SIZE; + useEffect(() => { + dispatch( + queryJobTitleTimeAndSalaryStatistics({ + jobTitle: pageName, + }), + ); + }, [dispatch, pageName]); + useEffect(() => { dispatch( queryJobTitleTimeAndSalary({ @@ -64,12 +89,11 @@ const JobTitleTimeAndSalaryProvider = () => { fetchPermission(); }, [pageType, pageName, fetchPermission]); - const { - status, - salaryWorkTimes, - salaryWorkTimesCount, - salaryWorkTimeStatistics, - } = useTimeAndSalaryBox(pageName); + const { status, salaryWorkTimes, salaryWorkTimesCount } = useTimeAndSalaryBox( + pageName, + ); + + const salaryWorkTimeStatistics = useSalaryWorkTimeStatistics(pageName); return ( overviewBox overviewByName: {}, timeAndSalaryByName: {}, + timeAndSalaryStatisticsByName: {}, interviewExperiencesByName: {}, workExperiencesByName: {}, }; @@ -52,6 +54,15 @@ const reducer = createReducer(preloadedState, { }, }; }, + [SET_TIME_AND_SALARY_STATISTICS]: (state, { companyName, box }) => { + return { + ...state, + timeAndSalaryStatisticsByName: { + ...state.timeAndSalaryStatisticsByName, + [companyName]: box, + }, + }; + }, [SET_INTERVIEW_EXPERIENCES]: (state, { companyName, box }) => { return { ...state, diff --git a/src/reducers/jobTitleIndex.js b/src/reducers/jobTitleIndex.js index a26eda377..68b17e051 100644 --- a/src/reducers/jobTitleIndex.js +++ b/src/reducers/jobTitleIndex.js @@ -7,6 +7,7 @@ import { SET_TIME_AND_SALARY, SET_INTERVIEW_EXPERIENCES, SET_WORK_EXPERIENCES, + SET_TIME_AND_SALARY_STATISTICS, } from 'actions/jobTitle'; const preloadedState = { @@ -16,6 +17,7 @@ const preloadedState = { // jobTitle --> overviewBox overviewByName: {}, timeAndSalaryByName: {}, + timeAndSalaryStatisticsByName: {}, interviewExperiencesByName: {}, workExperiencesByName: {}, }; @@ -52,6 +54,15 @@ const reducer = createReducer(preloadedState, { }, }; }, + [SET_TIME_AND_SALARY_STATISTICS]: (state, { jobTitle, box }) => { + return { + ...state, + timeAndSalaryStatisticsByName: { + ...state.timeAndSalaryStatisticsByName, + [jobTitle]: box, + }, + }; + }, [SET_INTERVIEW_EXPERIENCES]: (state, { jobTitle, box }) => { return { ...state, diff --git a/src/selectors/companyAndJobTitle.js b/src/selectors/companyAndJobTitle.js index aec1791de..babd72e75 100644 --- a/src/selectors/companyAndJobTitle.js +++ b/src/selectors/companyAndJobTitle.js @@ -124,6 +124,13 @@ export const companyTimeAndSalaryBoxSelectorByName = companyName => state => { return state.companyIndex.timeAndSalaryByName[companyName] || getUnfetched(); }; +export const companyTimeAndSalaryStatisticsBoxSelectorByName = companyName => state => { + return ( + state.companyIndex.timeAndSalaryStatisticsByName[companyName] || + getUnfetched() + ); +}; + export const companyInterviewExperiencesBoxSelectorByName = companyName => state => { return ( state.companyIndex.interviewExperiencesByName[companyName] || getUnfetched() @@ -153,6 +160,13 @@ export const jobTitleTimeAndSalaryBoxSelectorByName = jobTitle => state => { return state.jobTitleIndex.timeAndSalaryByName[jobTitle] || getUnfetched(); }; +export const jobTitleTimeAndSalaryStatisticsBoxSelectorByName = jobTitle => state => { + return ( + state.jobTitleIndex.timeAndSalaryStatisticsByName[jobTitle] || + getUnfetched() + ); +}; + export const jobTitleInterviewExperiencesBoxSelectorByName = jobTitle => state => { return ( state.jobTitleIndex.interviewExperiencesByName[jobTitle] || getUnfetched() From e58ac8057293b5bd5f46cc03ca0897b7e498d561 Mon Sep 17 00:00:00 2001 From: Peteranny Date: Wed, 28 Aug 2024 00:55:30 +0800 Subject: [PATCH 05/13] update debounce to 1.5s --- src/components/CompanyAndJobTitle/Searchbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CompanyAndJobTitle/Searchbar.js b/src/components/CompanyAndJobTitle/Searchbar.js index 4a40da603..413997192 100644 --- a/src/components/CompanyAndJobTitle/Searchbar.js +++ b/src/components/CompanyAndJobTitle/Searchbar.js @@ -64,7 +64,7 @@ const Searchbar = ({ className, label, placeholder, onSubmit, pageType }) => { break; } }, - 300, + 1500, [searchText], ); From 29faf3e7c24557dc9c022075091172e0163f530b Mon Sep 17 00:00:00 2001 From: Peteranny Date: Wed, 28 Aug 2024 01:07:02 +0800 Subject: [PATCH 06/13] remove unneeded --- src/components/Company/CompanyTimeAndSalaryProvider.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Company/CompanyTimeAndSalaryProvider.js b/src/components/Company/CompanyTimeAndSalaryProvider.js index e68b7c075..7fda6917f 100644 --- a/src/components/Company/CompanyTimeAndSalaryProvider.js +++ b/src/components/Company/CompanyTimeAndSalaryProvider.js @@ -43,7 +43,6 @@ const useTimeAndSalaryBox = pageName => { status: statusSelector(company), salaryWorkTimes: salaryWorkTimesSelector(company), salaryWorkTimesCount: salaryWorkTimesCountSelector(company), - salaryWorkTimeStatistics: salaryWorkTimeStatisticsSelector(company), }; }, [pageName], From 3354aea8ce8b3020d2f16c44957af752434e74af Mon Sep 17 00:00:00 2001 From: "peter.shih" Date: Wed, 28 Aug 2024 10:37:24 +0800 Subject: [PATCH 07/13] ssr statistics --- src/components/Company/CompanyTimeAndSalaryProvider.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/Company/CompanyTimeAndSalaryProvider.js b/src/components/Company/CompanyTimeAndSalaryProvider.js index 7fda6917f..3d1d35d02 100644 --- a/src/components/Company/CompanyTimeAndSalaryProvider.js +++ b/src/components/Company/CompanyTimeAndSalaryProvider.js @@ -118,7 +118,12 @@ CompanyTimeAndSalaryProvider.fetchData = ({ const jobTitle = searchTextFromQuerySelector(query) || undefined; const start = (page - 1) * PAGE_SIZE; const limit = PAGE_SIZE; - return dispatch( + const dispatchTimeAndSalaryStatistics = dispatch( + queryCompanyTimeAndSalaryStatistics({ + companyName: pageName, + }), + ); + const dispatchTimeAndSalary = dispatch( queryCompanyTimeAndSalary({ companyName: pageName, jobTitle, @@ -126,6 +131,7 @@ CompanyTimeAndSalaryProvider.fetchData = ({ limit, }), ); + return Promise.all([dispatchTimeAndSalary, dispatchTimeAndSalaryStatistics]); }; export default CompanyTimeAndSalaryProvider; From 701d493d358d22e403ce23e859623a3b51b763b9 Mon Sep 17 00:00:00 2001 From: "peter.shih" Date: Wed, 28 Aug 2024 10:43:13 +0800 Subject: [PATCH 08/13] remove unneeded fields from overview --- .../TimeAndSalary/OvertimeSection.js | 15 +++++++- src/graphql/company.js | 34 ------------------- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js b/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js index 89182ac0b..e78136a76 100644 --- a/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js +++ b/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js @@ -30,7 +30,20 @@ const OvertimeSection = ({ statistics }) => { }; OvertimeSection.propTypes = { - statistics: PropTypes.object.isRequired, + statistics: PropTypes.shape({ + average_estimated_hourly_wage: PropTypes.number.isRequired, + count: PropTypes.number.isRequired, + has_compensatory_dayoff_count: PropTypes.shape({ + no: PropTypes.number.isRequired, + unknown: PropTypes.number.isRequired, + yes: PropTypes.number.isRequired, + }).isRequired, + is_overtime_salary_legal_count: PropTypes.shape({ + no: PropTypes.number.isRequired, + unknown: PropTypes.number.isRequired, + yes: PropTypes.number.isRequired, + }).isRequired, + }).isRequired, }; export default OvertimeSection; diff --git a/src/graphql/company.js b/src/graphql/company.js index 7fb5780ab..20c564233 100644 --- a/src/graphql/company.js +++ b/src/graphql/company.js @@ -96,8 +96,6 @@ export const queryCompanyOverviewGql = /* GraphQL */ ` } } salary_work_time_statistics { - count - average_estimated_hourly_wage average_week_work_time overtime_frequency_count { seldom @@ -105,21 +103,6 @@ export const queryCompanyOverviewGql = /* GraphQL */ ` usually almost_everyday } - is_overtime_salary_legal_count { - yes - no - unknown - } - has_compensatory_dayoff_count { - yes - no - unknown - } - has_overtime_salary_count { - yes - no - unknown - } job_average_salaries { job_title { name @@ -178,13 +161,6 @@ export const getCompanyTimeAndSalaryStatisticsQuery = /* GraphQL */ ` salary_work_time_statistics { count average_estimated_hourly_wage - average_week_work_time - overtime_frequency_count { - seldom - sometimes - usually - almost_everyday - } is_overtime_salary_legal_count { yes no @@ -200,16 +176,6 @@ export const getCompanyTimeAndSalaryStatisticsQuery = /* GraphQL */ ` no unknown } - job_average_salaries { - job_title { - name - } - average_salary { - type - amount - } - data_count - } } } } From 956a7e356174cf95403c91f6c51dca48cdf6d6f2 Mon Sep 17 00:00:00 2001 From: "peter.shih" Date: Wed, 28 Aug 2024 12:39:34 +0800 Subject: [PATCH 09/13] update prop types --- .../TimeAndSalary/common/OvertimeBlock.js | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/components/TimeAndSalary/common/OvertimeBlock.js b/src/components/TimeAndSalary/common/OvertimeBlock.js index 09055b9ee..408db3ab5 100644 --- a/src/components/TimeAndSalary/common/OvertimeBlock.js +++ b/src/components/TimeAndSalary/common/OvertimeBlock.js @@ -82,7 +82,25 @@ const OvertimeBlock = ({ type, heading, statistics }) => ( OvertimeBlock.propTypes = { heading: PropTypes.string.isRequired, - statistics: PropTypes.object.isRequired, + statistics: PropTypes.shape({ + average_estimated_hourly_wage: PropTypes.number.isRequired, + count: PropTypes.number.isRequired, + has_compensatory_dayoff_count: PropTypes.shape({ + no: PropTypes.number.isRequired, + unknown: PropTypes.number.isRequired, + yes: PropTypes.number.isRequired, + }).isRequired, + has_overtime_salary_count: PropTypes.shape({ + no: PropTypes.number.isRequired, + unknown: PropTypes.number.isRequired, + yes: PropTypes.number.isRequired, + }).isRequired, + is_overtime_salary_legal_count: PropTypes.shape({ + no: PropTypes.number.isRequired, + unknown: PropTypes.number.isRequired, + yes: PropTypes.number.isRequired, + }), + }).isRequired, type: PropTypes.oneOf(['salary', 'dayoff']).isRequired, }; From 1cd3648388c42477dc427773bc731b9968cac42e Mon Sep 17 00:00:00 2001 From: "peter.shih" Date: Wed, 28 Aug 2024 12:44:05 +0800 Subject: [PATCH 10/13] remove unused graphql --- .../TimeAndSalary/OvertimeSection.js | 1 - .../TimeAndSalary/TimeAndSalary.js | 1 - .../CompanyAndJobTitle/TimeAndSalary/index.js | 1 - .../TimeAndSalary/common/OvertimeBlock.js | 1 - src/graphql/company.js | 1 - src/graphql/jobTitle.js | 35 ------------------- 6 files changed, 40 deletions(-) diff --git a/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js b/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js index e78136a76..692ac9320 100644 --- a/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js +++ b/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js @@ -31,7 +31,6 @@ const OvertimeSection = ({ statistics }) => { OvertimeSection.propTypes = { statistics: PropTypes.shape({ - average_estimated_hourly_wage: PropTypes.number.isRequired, count: PropTypes.number.isRequired, has_compensatory_dayoff_count: PropTypes.shape({ no: PropTypes.number.isRequired, diff --git a/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js b/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js index b79bd3c8e..64c5e8118 100644 --- a/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js +++ b/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js @@ -65,7 +65,6 @@ TimeAndSalary.propTypes = { pageSize: PropTypes.number.isRequired, pageType: PropTypes.string, salaryWorkTimeStatistics: PropTypes.shape({ - average_estimated_hourly_wage: PropTypes.number, average_week_work_time: PropTypes.number, count: PropTypes.number, }), diff --git a/src/components/CompanyAndJobTitle/TimeAndSalary/index.js b/src/components/CompanyAndJobTitle/TimeAndSalary/index.js index 36b6236b9..518a485e2 100644 --- a/src/components/CompanyAndJobTitle/TimeAndSalary/index.js +++ b/src/components/CompanyAndJobTitle/TimeAndSalary/index.js @@ -54,7 +54,6 @@ TimeAndSalary.propTypes = { pageSize: PropTypes.number.isRequired, pageType: PropTypes.string, salaryWorkTimeStatistics: PropTypes.shape({ - average_estimated_hourly_wage: PropTypes.number, average_week_work_time: PropTypes.number, count: PropTypes.number, }), diff --git a/src/components/TimeAndSalary/common/OvertimeBlock.js b/src/components/TimeAndSalary/common/OvertimeBlock.js index 408db3ab5..23ce7692b 100644 --- a/src/components/TimeAndSalary/common/OvertimeBlock.js +++ b/src/components/TimeAndSalary/common/OvertimeBlock.js @@ -83,7 +83,6 @@ const OvertimeBlock = ({ type, heading, statistics }) => ( OvertimeBlock.propTypes = { heading: PropTypes.string.isRequired, statistics: PropTypes.shape({ - average_estimated_hourly_wage: PropTypes.number.isRequired, count: PropTypes.number.isRequired, has_compensatory_dayoff_count: PropTypes.shape({ no: PropTypes.number.isRequired, diff --git a/src/graphql/company.js b/src/graphql/company.js index 20c564233..c57ca43fe 100644 --- a/src/graphql/company.js +++ b/src/graphql/company.js @@ -160,7 +160,6 @@ export const getCompanyTimeAndSalaryStatisticsQuery = /* GraphQL */ ` name salary_work_time_statistics { count - average_estimated_hourly_wage is_overtime_salary_legal_count { yes no diff --git a/src/graphql/jobTitle.js b/src/graphql/jobTitle.js index d2d2c8f8d..3a181a1b3 100644 --- a/src/graphql/jobTitle.js +++ b/src/graphql/jobTitle.js @@ -105,8 +105,6 @@ export const queryJobTitleOverviewGql = /* GraphQL */ ` } } salary_work_time_statistics { - count - average_estimated_hourly_wage average_week_work_time overtime_frequency_count { seldom @@ -114,21 +112,6 @@ export const queryJobTitleOverviewGql = /* GraphQL */ ` usually almost_everyday } - is_overtime_salary_legal_count { - yes - no - unknown - } - has_compensatory_dayoff_count { - yes - no - unknown - } - has_overtime_salary_count { - yes - no - unknown - } } salary_distribution { bins { @@ -191,14 +174,6 @@ export const getJobTitleTimeAndSalaryStatisticsQuery = /* GraphQL */ ` name salary_work_time_statistics { count - average_estimated_hourly_wage - average_week_work_time - overtime_frequency_count { - seldom - sometimes - usually - almost_everyday - } is_overtime_salary_legal_count { yes no @@ -215,16 +190,6 @@ export const getJobTitleTimeAndSalaryStatisticsQuery = /* GraphQL */ ` unknown } } - salary_distribution { - bins { - data_count - range { - type - from - to - } - } - } } } `; From a8af95d0b6bb390e1e8c6a99d1a83426657dae5b Mon Sep 17 00:00:00 2001 From: "peter.shih" Date: Wed, 28 Aug 2024 12:49:28 +0800 Subject: [PATCH 11/13] undo unneeded prop types --- .../TimeAndSalary/OvertimeSection.js | 14 +------------- .../CompanyAndJobTitle/TimeAndSalary/index.js | 5 +---- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js b/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js index 692ac9320..89182ac0b 100644 --- a/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js +++ b/src/components/CompanyAndJobTitle/TimeAndSalary/OvertimeSection.js @@ -30,19 +30,7 @@ const OvertimeSection = ({ statistics }) => { }; OvertimeSection.propTypes = { - statistics: PropTypes.shape({ - count: PropTypes.number.isRequired, - has_compensatory_dayoff_count: PropTypes.shape({ - no: PropTypes.number.isRequired, - unknown: PropTypes.number.isRequired, - yes: PropTypes.number.isRequired, - }).isRequired, - is_overtime_salary_legal_count: PropTypes.shape({ - no: PropTypes.number.isRequired, - unknown: PropTypes.number.isRequired, - yes: PropTypes.number.isRequired, - }).isRequired, - }).isRequired, + statistics: PropTypes.object.isRequired, }; export default OvertimeSection; diff --git a/src/components/CompanyAndJobTitle/TimeAndSalary/index.js b/src/components/CompanyAndJobTitle/TimeAndSalary/index.js index 518a485e2..b5330853e 100644 --- a/src/components/CompanyAndJobTitle/TimeAndSalary/index.js +++ b/src/components/CompanyAndJobTitle/TimeAndSalary/index.js @@ -53,10 +53,7 @@ TimeAndSalary.propTypes = { pageName: PropTypes.string, pageSize: PropTypes.number.isRequired, pageType: PropTypes.string, - salaryWorkTimeStatistics: PropTypes.shape({ - average_week_work_time: PropTypes.number, - count: PropTypes.number, - }), + salaryWorkTimeStatistics: PropTypes.object.isRequired, salaryWorkTimes: PropTypes.array, status: PropTypes.string.isRequired, tabType: PropTypes.string, From c161c58c09a30af2ac1a4e87add7015472a7926f Mon Sep 17 00:00:00 2001 From: "peter.shih" Date: Wed, 28 Aug 2024 13:31:39 +0800 Subject: [PATCH 12/13] fix unfetched statistics prop types --- src/components/TimeAndSalary/common/OvertimeBlock.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/TimeAndSalary/common/OvertimeBlock.js b/src/components/TimeAndSalary/common/OvertimeBlock.js index 23ce7692b..67995b8cb 100644 --- a/src/components/TimeAndSalary/common/OvertimeBlock.js +++ b/src/components/TimeAndSalary/common/OvertimeBlock.js @@ -83,17 +83,17 @@ const OvertimeBlock = ({ type, heading, statistics }) => ( OvertimeBlock.propTypes = { heading: PropTypes.string.isRequired, statistics: PropTypes.shape({ - count: PropTypes.number.isRequired, + count: PropTypes.number, has_compensatory_dayoff_count: PropTypes.shape({ no: PropTypes.number.isRequired, unknown: PropTypes.number.isRequired, yes: PropTypes.number.isRequired, - }).isRequired, + }), has_overtime_salary_count: PropTypes.shape({ no: PropTypes.number.isRequired, unknown: PropTypes.number.isRequired, yes: PropTypes.number.isRequired, - }).isRequired, + }), is_overtime_salary_legal_count: PropTypes.shape({ no: PropTypes.number.isRequired, unknown: PropTypes.number.isRequired, From 8913f656270c12bd3ad1916af460f7b021d86834 Mon Sep 17 00:00:00 2001 From: "peter.shih" Date: Wed, 28 Aug 2024 13:35:38 +0800 Subject: [PATCH 13/13] remove unused props --- .../CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js b/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js index 64c5e8118..11b6ac516 100644 --- a/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js +++ b/src/components/CompanyAndJobTitle/TimeAndSalary/TimeAndSalary.js @@ -12,7 +12,6 @@ import { useQuery } from 'hooks/routing'; const TimeAndSalary = ({ salaryWorkTimes, - salaryWorkTimeStatistics, pageType, pageName, tabType, @@ -64,10 +63,6 @@ TimeAndSalary.propTypes = { pageName: PropTypes.string, pageSize: PropTypes.number.isRequired, pageType: PropTypes.string, - salaryWorkTimeStatistics: PropTypes.shape({ - average_week_work_time: PropTypes.number, - count: PropTypes.number, - }), salaryWorkTimes: PropTypes.array, tabType: PropTypes.string, totalCount: PropTypes.number.isRequired,