From df291ee3da09e0a58aeb6ce225c64e242519d936 Mon Sep 17 00:00:00 2001 From: Ivar Nakken Date: Sun, 15 Dec 2024 15:56:49 +0100 Subject: [PATCH 1/8] Implement filtering on /companies Search on names and descriptions, and filter out inactive companies. --- .../admin/email/components/EmailLists.tsx | 3 +- .../admin/email/components/EmailUsers.tsx | 3 +- .../articles/components/ArticleList.tsx | 3 +- .../company/components/CompaniesPage.tsx | 70 +++++++++++++++++-- 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/app/routes/admin/email/components/EmailLists.tsx b/app/routes/admin/email/components/EmailLists.tsx index 3e6d133e69..fad28d702f 100644 --- a/app/routes/admin/email/components/EmailLists.tsx +++ b/app/routes/admin/email/components/EmailLists.tsx @@ -7,6 +7,7 @@ import Tag from 'app/components/Tags/Tag'; import { selectEmailLists } from 'app/reducers/emailLists'; import { selectPaginationNext } from 'app/reducers/selectors'; import { useAppDispatch, useAppSelector } from 'app/store/hooks'; +import { EntityType } from 'app/store/models/entities'; import useQuery from 'app/utils/useQuery'; const emailListsDefaultQuery = { @@ -21,7 +22,7 @@ const EmailLists = () => { const { pagination } = useAppSelector((state) => selectPaginationNext({ endpoint: '/email-lists/', - entity: 'emailLists', + entity: EntityType.EmailLists, query, })(state), ); diff --git a/app/routes/admin/email/components/EmailUsers.tsx b/app/routes/admin/email/components/EmailUsers.tsx index d35a649639..2d62083ba0 100644 --- a/app/routes/admin/email/components/EmailUsers.tsx +++ b/app/routes/admin/email/components/EmailUsers.tsx @@ -11,6 +11,7 @@ import { selectTransformedEmailUsers } from 'app/reducers/emailUsers'; import { selectGroupsByType } from 'app/reducers/groups'; import { selectPaginationNext } from 'app/reducers/selectors'; import { useAppDispatch, useAppSelector } from 'app/store/hooks'; +import { EntityType } from 'app/store/models/entities'; import useQuery from 'app/utils/useQuery'; import type { ColumnProps } from 'app/components/Table'; @@ -35,7 +36,7 @@ const EmailUsers = () => { const { pagination } = useAppSelector((state) => selectPaginationNext({ endpoint: '/email-users/', - entity: 'emailUsers', + entity: EntityType.EmailUsers, query, })(state), ); diff --git a/app/routes/articles/components/ArticleList.tsx b/app/routes/articles/components/ArticleList.tsx index 2165375608..aa2eda4a2d 100644 --- a/app/routes/articles/components/ArticleList.tsx +++ b/app/routes/articles/components/ArticleList.tsx @@ -13,6 +13,7 @@ import { selectPaginationNext } from 'app/reducers/selectors'; import { selectPopularTags } from 'app/reducers/tags'; import { selectUsersByIds } from 'app/reducers/users'; import { useAppDispatch, useAppSelector } from 'app/store/hooks'; +import { EntityType } from 'app/store/models/entities'; import useQuery from 'app/utils/useQuery'; import styles from '../articles.module.css'; import type { PublicArticle } from 'app/store/models/Article'; @@ -76,7 +77,7 @@ const ArticleList = () => { selectPaginationNext({ endpoint: `/articles/`, query, - entity: 'articles', + entity: EntityType.Articles, })(state), ); const articles: PublicArticle[] = useAppSelector((state) => diff --git a/app/routes/company/components/CompaniesPage.tsx b/app/routes/company/components/CompaniesPage.tsx index 35ce22cf8d..d1656c2fd3 100644 --- a/app/routes/company/components/CompaniesPage.tsx +++ b/app/routes/company/components/CompaniesPage.tsx @@ -7,17 +7,22 @@ import { Image, Page, LinkButton, + filterSidebar, + FilterSection, } from '@webkom/lego-bricks'; import { usePreparedEffect } from '@webkom/react-prepare'; -import { useState } from 'react'; +import { useState, useMemo } from 'react'; import { Helmet } from 'react-helmet-async'; import InfiniteScroll from 'react-infinite-scroller'; import { Link } from 'react-router-dom'; import { fetchAll } from 'app/actions/CompanyActions'; -import { selectActiveCompanies } from 'app/reducers/companies'; +import { CheckBox, TextInput } from 'app/components/Form'; +import { selectAllCompanies } from 'app/reducers/companies'; import { selectPaginationNext } from 'app/reducers/selectors'; import { useAppDispatch, useAppSelector } from 'app/store/hooks'; +import { EntityType } from 'app/store/models/entities'; import utilities from 'app/styles/utilities.css'; +import useQuery from 'app/utils/useQuery'; import styles from './CompaniesPage.module.css'; import type { ListCompany } from 'app/store/models/Company'; @@ -84,20 +89,48 @@ const CompanyList = ({ companies = [] }: CompanyListProps) => ( ); +export const companiesDefaultQuery = { + search: '', + showInactive: 'false' as 'true' | 'false', +}; + +const filterCompanies = ( + companies: ListCompany[], + query: typeof companiesDefaultQuery, +) => { + return companies.filter((company) => { + const searchMatch = + !query.search || + company.name.toLowerCase().includes(query.search.toLowerCase()) || + company.description?.toLowerCase().includes(query.search.toLowerCase()); + + const activeMatch = !query.showInactive || company.active !== false; + + return searchMatch && activeMatch; + }); +}; + const CompaniesPage = () => { const [expanded, setExpanded] = useState(false); + const { query, setQueryValue } = useQuery(companiesDefaultQuery); - const companies = useAppSelector(selectActiveCompanies); + const companies = useAppSelector(selectAllCompanies); + const inactiveCompanies = companies.filter((company) => !company.active); + console.log('inactiveCompanies', inactiveCompanies); const { pagination } = useAppSelector((state) => selectPaginationNext({ query: {}, - entity: 'companies', + entity: EntityType.Companies, endpoint: '/companies/', })(state), ); - const dispatch = useAppDispatch(); + const filteredCompanies = useMemo( + () => filterCompanies(companies, query), + [companies, query], + ); + const dispatch = useAppDispatch(); const actionGrant = useAppSelector((state) => state.companies.actionGrant); usePreparedEffect( @@ -109,6 +142,31 @@ const CompaniesPage = () => { return ( + + setQueryValue('search')(e.target.value)} + /> + + + setQueryValue('showInactive')( + query.showInactive === 'true' ? 'false' : 'true', + ) + } + /> + + ), + })} actionButtons={ (actionGrant.includes('create') || actionGrant.includes('edit')) && ( Bedriftsdatabasen @@ -181,7 +239,7 @@ const CompaniesPage = () => { initialLoad={false} loader={} > - + ); From a6c0d39a6a8bf7bda932ff2881d0701fcb631fab Mon Sep 17 00:00:00 2001 From: Ivar Nakken Date: Sun, 15 Dec 2024 16:54:58 +0100 Subject: [PATCH 2/8] Fix "show all semesters" option on company interest list Choosing the "show all semesters" option would just default to the current semester. --- app/routes/companyInterest/components/CompanyInterestList.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/routes/companyInterest/components/CompanyInterestList.tsx b/app/routes/companyInterest/components/CompanyInterestList.tsx index 8885d78064..03f8d1fee9 100644 --- a/app/routes/companyInterest/components/CompanyInterestList.tsx +++ b/app/routes/companyInterest/components/CompanyInterestList.tsx @@ -60,6 +60,8 @@ const CompanyInterestList = () => { slug: string | undefined, companySemesters: CompanySemester[], ) => { + if (slug === '') return null; + if (slug) { const companySemester = getCompanySemesterBySlug(slug, companySemesters); if (companySemester) return companySemester; From 1a008769285c7f8be4ab64abb21d2273ef0ccfa0 Mon Sep 17 00:00:00 2001 From: Ivar Nakken Date: Sun, 15 Dec 2024 17:06:33 +0100 Subject: [PATCH 3/8] Support search on company interest list --- .../components/CompanyInterestList.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/app/routes/companyInterest/components/CompanyInterestList.tsx b/app/routes/companyInterest/components/CompanyInterestList.tsx index 03f8d1fee9..e3a15155b3 100644 --- a/app/routes/companyInterest/components/CompanyInterestList.tsx +++ b/app/routes/companyInterest/components/CompanyInterestList.tsx @@ -46,6 +46,7 @@ type SemesterOptionType = { const defaultCompanyInterestsQuery = { semester: '', event: CompanyInterestEventType.All, + companyName: '', }; const CompanyInterestList = () => { @@ -53,7 +54,9 @@ const CompanyInterestList = () => { { url: string; filename: string } | undefined >(undefined); - const { query, setQueryValue } = useQuery(defaultCompanyInterestsQuery); + const { query, setQuery, setQueryValue } = useQuery( + defaultCompanyInterestsQuery, + ); const companySemesters = useAppSelector(selectAllCompanySemesters); const resolveCurrentSemester = ( @@ -117,10 +120,10 @@ const CompanyInterestList = () => { ), [query], ); + usePreparedEffect( 'fetchCompanyInterestListSemesters', () => dispatch(fetchSemesters()), - [], ); @@ -152,6 +155,8 @@ const CompanyInterestList = () => { { title: 'Bedriftsnavn', dataIndex: 'companyName', + search: true, + inlineFiltering: true, render: (companyName: string, companyInterest) => ( {companyInterest.company ? companyInterest.company.name : companyName} @@ -182,7 +187,12 @@ const CompanyInterestList = () => { }} > {({ openConfirmModal }) => ( - } danger /> + } + size={18} + danger + /> )} @@ -317,6 +327,8 @@ const CompanyInterestList = () => { }} hasMore={hasMore} loading={fetching} + filters={query} + onChange={setQuery} data={companyInterestList} /> From 773ac5400f109047a5328eb6494ea46d57c591f5 Mon Sep 17 00:00:00 2001 From: Ivar Nakken Date: Sun, 15 Dec 2024 19:21:17 +0100 Subject: [PATCH 4/8] Simplify bdb routing by nesting company interests inside /bdb Company interests are now under /bdb/company-interests. This follows the routing patterns seen on other pages, and should therefore be more "clear" --- app/actions/CompanyActions.ts | 2 +- app/reducers/companySemesters.ts | 2 +- .../components/CompanyInterest.module.css | 0 .../components/CompanyInterestList.tsx | 8 +++---- .../components/CompanyInterestPage.tsx | 4 ++-- .../components/CompanySemesterGUI.tsx | 5 +++- .../components/Translations.ts | 0 .../components}/companyInterest/utils.tsx | 0 app/routes/bdb/index.tsx | 16 +++++++++++++ app/routes/bdb/utils.tsx | 6 +++-- app/routes/companyInterest/index.tsx | 23 ------------------- app/routes/index.tsx | 6 ++--- 12 files changed, 34 insertions(+), 38 deletions(-) rename app/routes/{ => bdb/components}/companyInterest/components/CompanyInterest.module.css (100%) rename app/routes/{ => bdb/components}/companyInterest/components/CompanyInterestList.tsx (97%) rename app/routes/{ => bdb/components}/companyInterest/components/CompanyInterestPage.tsx (99%) rename app/routes/{ => bdb/components}/companyInterest/components/CompanySemesterGUI.tsx (97%) rename app/routes/{ => bdb/components}/companyInterest/components/Translations.ts (100%) rename app/routes/{ => bdb/components}/companyInterest/utils.tsx (100%) delete mode 100644 app/routes/companyInterest/index.tsx diff --git a/app/actions/CompanyActions.ts b/app/actions/CompanyActions.ts index 0192c30a67..a780cc2a9c 100644 --- a/app/actions/CompanyActions.ts +++ b/app/actions/CompanyActions.ts @@ -4,8 +4,8 @@ import { companySemesterSchema, eventSchema, } from 'app/reducers'; +import { semesterToText } from 'app/routes/bdb/components/companyInterest/utils'; import createQueryString from 'app/utils/createQueryString'; -import { semesterToText } from '../routes/companyInterest/utils'; import { Company, Event } from './ActionTypes'; import type { EntityId } from '@reduxjs/toolkit'; import type { FormValues as CompanyContactEditorFormValues } from 'app/routes/bdb/components/CompanyContactEditor'; diff --git a/app/reducers/companySemesters.ts b/app/reducers/companySemesters.ts index 7dde8ea068..c5b7c0dec8 100644 --- a/app/reducers/companySemesters.ts +++ b/app/reducers/companySemesters.ts @@ -1,6 +1,6 @@ import { createSlice } from '@reduxjs/toolkit'; import { createSelector } from 'reselect'; -import { sortSemesterChronologically } from 'app/routes/companyInterest/utils'; +import { sortSemesterChronologically } from 'app/routes/bdb/components/companyInterest/utils'; import { EntityType } from 'app/store/models/entities'; import createLegoAdapter from 'app/utils/legoAdapter/createLegoAdapter'; import { Company } from '../actions/ActionTypes'; diff --git a/app/routes/companyInterest/components/CompanyInterest.module.css b/app/routes/bdb/components/companyInterest/components/CompanyInterest.module.css similarity index 100% rename from app/routes/companyInterest/components/CompanyInterest.module.css rename to app/routes/bdb/components/companyInterest/components/CompanyInterest.module.css diff --git a/app/routes/companyInterest/components/CompanyInterestList.tsx b/app/routes/bdb/components/companyInterest/components/CompanyInterestList.tsx similarity index 97% rename from app/routes/companyInterest/components/CompanyInterestList.tsx rename to app/routes/bdb/components/companyInterest/components/CompanyInterestList.tsx index e3a15155b3..f679298b64 100644 --- a/app/routes/companyInterest/components/CompanyInterestList.tsx +++ b/app/routes/bdb/components/companyInterest/components/CompanyInterestList.tsx @@ -158,7 +158,7 @@ const CompanyInterestList = () => { search: true, inlineFiltering: true, render: (companyName: string, companyInterest) => ( - + {companyInterest.company ? companyInterest.company.name : companyName} ), @@ -229,9 +229,9 @@ const CompanyInterestList = () => { return ( + Ny bedriftsinteresse } @@ -269,7 +269,7 @@ const CompanyInterestList = () => { isClearable={false} /> - + Endre aktive semestre diff --git a/app/routes/companyInterest/components/CompanyInterestPage.tsx b/app/routes/bdb/components/companyInterest/components/CompanyInterestPage.tsx similarity index 99% rename from app/routes/companyInterest/components/CompanyInterestPage.tsx rename to app/routes/bdb/components/companyInterest/components/CompanyInterestPage.tsx index a2a38863e3..7398bc556a 100644 --- a/app/routes/companyInterest/components/CompanyInterestPage.tsx +++ b/app/routes/bdb/components/companyInterest/components/CompanyInterestPage.tsx @@ -437,7 +437,7 @@ const CompanyInterestPage = () => { : createCompanyInterest(newData, isEnglish), ).then(() => { navigate( - allowedBdb ? '/company-interest' : '/pages/bedrifter/for-bedrifter', + allowedBdb ? '/bdb/company-interest' : '/pages/bedrifter/for-bedrifter', ); }); }; @@ -506,7 +506,7 @@ const CompanyInterestPage = () => { return ( diff --git a/app/routes/companyInterest/components/CompanySemesterGUI.tsx b/app/routes/bdb/components/companyInterest/components/CompanySemesterGUI.tsx similarity index 97% rename from app/routes/companyInterest/components/CompanySemesterGUI.tsx rename to app/routes/bdb/components/companyInterest/components/CompanySemesterGUI.tsx index 0c997f004a..e712cb0d73 100644 --- a/app/routes/companyInterest/components/CompanySemesterGUI.tsx +++ b/app/routes/bdb/components/companyInterest/components/CompanySemesterGUI.tsx @@ -40,7 +40,10 @@ const validate = createValidator({ const CompanySemesterGUI = () => { return ( - + diff --git a/app/routes/companyInterest/components/Translations.ts b/app/routes/bdb/components/companyInterest/components/Translations.ts similarity index 100% rename from app/routes/companyInterest/components/Translations.ts rename to app/routes/bdb/components/companyInterest/components/Translations.ts diff --git a/app/routes/companyInterest/utils.tsx b/app/routes/bdb/components/companyInterest/utils.tsx similarity index 100% rename from app/routes/companyInterest/utils.tsx rename to app/routes/bdb/components/companyInterest/utils.tsx diff --git a/app/routes/bdb/index.tsx b/app/routes/bdb/index.tsx index 0b0447aa67..bbe75e09e2 100644 --- a/app/routes/bdb/index.tsx +++ b/app/routes/bdb/index.tsx @@ -9,6 +9,15 @@ const AddSemester = loadable(() => import('./components/AddSemester')); const CompanyContactEditor = loadable( () => import('./components/CompanyContactEditor'), ); +const CompanyInterestList = loadable( + () => import('./components/companyInterest/components/CompanyInterestList'), +); +const CompanyInterestPage = loadable( + () => import('./components/companyInterest/components/CompanyInterestPage'), +); +const CompanySemesterGUI = loadable( + () => import('./components/companyInterest/components/CompanySemesterGUI'), +); const bdbRoute: RouteObject[] = [ { index: true, Component: BdbPage }, @@ -21,6 +30,13 @@ const bdbRoute: RouteObject[] = [ path: ':companyId/company-contacts/:companyContactId', Component: CompanyContactEditor, }, + { path: 'company-interest', Component: CompanyInterestList }, + { path: 'company-interest/create', Component: CompanyInterestPage }, + { path: 'company-interest/semesters', Component: CompanySemesterGUI }, + { + path: 'company-interest/:companyInterestId/edit', + Component: CompanyInterestPage, + }, { path: '*', children: pageNotFound }, ]; diff --git a/app/routes/bdb/utils.tsx b/app/routes/bdb/utils.tsx index 356e308606..add8b3d92c 100644 --- a/app/routes/bdb/utils.tsx +++ b/app/routes/bdb/utils.tsx @@ -236,7 +236,9 @@ export const getContactStatuses = ( export const BdbTabs = () => ( <> - Bedriftsinteresser - BDB + Semesterstatuser + + Bedriftsinteresser + ); diff --git a/app/routes/companyInterest/index.tsx b/app/routes/companyInterest/index.tsx deleted file mode 100644 index 382d72119c..0000000000 --- a/app/routes/companyInterest/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import loadable from '@loadable/component'; -import pageNotFound from '../pageNotFound'; -import type { RouteObject } from 'react-router-dom'; - -const CompanyInterestList = loadable( - () => import('./components/CompanyInterestList'), -); -const CompanyInterestPage = loadable( - () => import('./components/CompanyInterestPage'), -); -const CompanySemesterGUI = loadable( - () => import('./components/CompanySemesterGUI'), -); - -const companyInterestRoute: RouteObject[] = [ - { index: true, Component: CompanyInterestList }, - { path: 'create', Component: CompanyInterestPage }, - { path: 'semesters', Component: CompanySemesterGUI }, - { path: ':companyInterestId/edit', Component: CompanyInterestPage }, - { path: '*', children: pageNotFound }, -]; - -export default companyInterestRoute; diff --git a/app/routes/index.tsx b/app/routes/index.tsx index 07670bf346..3b84edf4c0 100644 --- a/app/routes/index.tsx +++ b/app/routes/index.tsx @@ -9,7 +9,6 @@ import authRoute from './auth'; import bdbRoute from './bdb'; import brandRoute from './brand'; import companyRoute from './company'; -import companyInterestRoute from './companyInterest'; import contactRoute from './contact'; import eventsRoute from './events'; import forumRoute from './forum'; @@ -29,7 +28,8 @@ import validatorRoute from './userValidator'; import usersRoute from './users'; const CompanyInterestPage = loadable( - () => import('./companyInterest/components/CompanyInterestPage'), + () => + import('./bdb/components/companyInterest/components/CompanyInterestPage'), ); const Frontpage = loadable(() => import('./frontpage')); @@ -47,8 +47,6 @@ export const routerConfig: RouteObject[] = [ { path: 'companies/*', children: companyRoute }, { path: 'register-interest', Component: CompanyInterestPage }, { path: 'interesse', Component: CompanyInterestPage }, - { path: 'companyInterest/*', children: companyInterestRoute }, - { path: 'company-interest/*', children: companyInterestRoute }, { path: 'contact', children: contactRoute }, { path: 'kontakt', children: contactRoute }, { path: 'events/*', children: eventsRoute }, From 12fcaccdbf1c2a96915938cb8a9c754dab96db45 Mon Sep 17 00:00:00 2001 From: Ivar Nakken Date: Wed, 18 Dec 2024 12:34:58 +0100 Subject: [PATCH 5/8] Fix search menu background after user has scrolled --- app/components/Search/Search.module.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/components/Search/Search.module.css b/app/components/Search/Search.module.css index 0520a1860c..f5394197b5 100644 --- a/app/components/Search/Search.module.css +++ b/app/components/Search/Search.module.css @@ -2,7 +2,7 @@ .wrapper { position: fixed; - inset: var(--development-banner-height) 0 0; + inset: 0; z-index: 200; overflow-y: auto; display: flex; @@ -29,7 +29,7 @@ } .inputContainer { - margin: 0 var(--spacing-md); + margin: var(--development-banner-height) var(--spacing-md) 0; height: var(--lego-header-height); border-bottom: 1.5px solid var(--border-gray); } From 45cea719049af73a84bfd7fec26eeeba3e90081e Mon Sep 17 00:00:00 2001 From: Ivar Nakken Date: Wed, 18 Dec 2024 13:01:29 +0100 Subject: [PATCH 6/8] Handle filtering of companies on the server --- app/actions/CompanyActions.ts | 11 +++- app/reducers/companies.ts | 7 ++- .../company/components/CompaniesPage.tsx | 58 +++++++++---------- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/app/actions/CompanyActions.ts b/app/actions/CompanyActions.ts index a780cc2a9c..e606bd828f 100644 --- a/app/actions/CompanyActions.ts +++ b/app/actions/CompanyActions.ts @@ -18,18 +18,25 @@ import type { SemesterStatus, } from 'app/store/models/Company'; import type CompanySemester from 'app/store/models/CompanySemester'; +import type { ParsedQs } from 'qs'; -export const fetchAll = ({ fetchMore }: { fetchMore: boolean }) => { +export const fetchAll = ({ + fetchMore, + query, +}: { + fetchMore: boolean; + query: ParsedQs; +}) => { return callAPI({ types: Company.FETCH, endpoint: '/companies/', schema: [companySchema], + query, pagination: { fetchNext: fetchMore, }, meta: { errorMessage: 'Henting av bedrifter feilet', - queryString: '', }, propagateError: true, }); diff --git a/app/reducers/companies.ts b/app/reducers/companies.ts index 7590aca6dc..dca6d5e34b 100644 --- a/app/reducers/companies.ts +++ b/app/reducers/companies.ts @@ -105,8 +105,11 @@ const companiesSlice = createSlice({ export default companiesSlice.reducer; -export const { selectAll: selectAllCompanies, selectById: selectCompanyById } = - legoAdapter.getSelectors((state: RootState) => state.companies); +export const { + selectAll: selectAllCompanies, + selectById: selectCompanyById, + selectAllPaginated: selectAllPaginatedCompanies, +} = legoAdapter.getSelectors((state: RootState) => state.companies); export type TransformedSemesterStatus = Overwrite< SemesterStatus, diff --git a/app/routes/company/components/CompaniesPage.tsx b/app/routes/company/components/CompaniesPage.tsx index d1656c2fd3..edf2d7a4bc 100644 --- a/app/routes/company/components/CompaniesPage.tsx +++ b/app/routes/company/components/CompaniesPage.tsx @@ -11,13 +11,13 @@ import { FilterSection, } from '@webkom/lego-bricks'; import { usePreparedEffect } from '@webkom/react-prepare'; -import { useState, useMemo } from 'react'; +import { useEffect, useState } from 'react'; import { Helmet } from 'react-helmet-async'; import InfiniteScroll from 'react-infinite-scroller'; import { Link } from 'react-router-dom'; import { fetchAll } from 'app/actions/CompanyActions'; import { CheckBox, TextInput } from 'app/components/Form'; -import { selectAllCompanies } from 'app/reducers/companies'; +import { selectAllPaginatedCompanies } from 'app/reducers/companies'; import { selectPaginationNext } from 'app/reducers/selectors'; import { useAppDispatch, useAppSelector } from 'app/store/hooks'; import { EntityType } from 'app/store/models/entities'; @@ -94,49 +94,44 @@ export const companiesDefaultQuery = { showInactive: 'false' as 'true' | 'false', }; -const filterCompanies = ( - companies: ListCompany[], - query: typeof companiesDefaultQuery, -) => { - return companies.filter((company) => { - const searchMatch = - !query.search || - company.name.toLowerCase().includes(query.search.toLowerCase()) || - company.description?.toLowerCase().includes(query.search.toLowerCase()); - - const activeMatch = !query.showInactive || company.active !== false; - - return searchMatch && activeMatch; - }); -}; - const CompaniesPage = () => { const [expanded, setExpanded] = useState(false); + const [debouncedSearch, setDebouncedSearch] = useState(''); const { query, setQueryValue } = useQuery(companiesDefaultQuery); - const companies = useAppSelector(selectAllCompanies); - const inactiveCompanies = companies.filter((company) => !company.active); - console.log('inactiveCompanies', inactiveCompanies); const { pagination } = useAppSelector((state) => selectPaginationNext({ - query: {}, + query: { ...query, search: debouncedSearch }, entity: EntityType.Companies, endpoint: '/companies/', })(state), ); - const filteredCompanies = useMemo( - () => filterCompanies(companies, query), - [companies, query], + const companies = useAppSelector((state) => + selectAllPaginatedCompanies(state, { pagination }), ); + useEffect(() => { + const timer = setTimeout(() => { + setDebouncedSearch(query.search); + }, 300); + + return () => clearTimeout(timer); + }, [query.search]); + const dispatch = useAppDispatch(); const actionGrant = useAppSelector((state) => state.companies.actionGrant); usePreparedEffect( 'fetchAllCompanies', - () => dispatch(fetchAll({ fetchMore: false })), - [], + () => + dispatch( + fetchAll({ + fetchMore: false, + query: { ...query, search: debouncedSearch }, + }), + ), + [query.showInactive, debouncedSearch], ); return ( @@ -234,12 +229,17 @@ const CompaniesPage = () => { loadMore={() => pagination.hasMore && !pagination.fetching && - dispatch(fetchAll({ fetchMore: true })) + dispatch( + fetchAll({ + fetchMore: true, + query: { ...query, search: debouncedSearch }, + }), + ) } initialLoad={false} loader={} > - + ); From 3333a405bd5e6a4d3211f2fb9e16ae86c4fb3a6c Mon Sep 17 00:00:00 2001 From: Ivar Nakken Date: Wed, 18 Dec 2024 16:29:51 +0100 Subject: [PATCH 7/8] Fix "read more" button on /companies Didn't seem to work on mobile, and I think it's clean to use it on all viewports. --- .../components/CompaniesPage.module.css | 17 ++---- .../company/components/CompaniesPage.tsx | 52 ++++++++++--------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/app/routes/company/components/CompaniesPage.module.css b/app/routes/company/components/CompaniesPage.module.css index 5c8f34c112..53baa4ff8d 100644 --- a/app/routes/company/components/CompaniesPage.module.css +++ b/app/routes/company/components/CompaniesPage.module.css @@ -83,6 +83,10 @@ .iconInfoPlacement { margin: var(--spacing-lg) 0; gap: var(--spacing-xl); + + @media (--small-viewport) { + gap: var(--spacing-md); + } } .infoText { @@ -91,16 +95,5 @@ } .readMore { - display: none; - color: var(--lego-red-color); -} - -@media (--small-viewport) { - .iconInfoPlacement { - gap: var(--spacing-md); - } - - .readMore { - display: contents; - } + margin-left: calc(-1 * var(--spacing-md)); } diff --git a/app/routes/company/components/CompaniesPage.tsx b/app/routes/company/components/CompaniesPage.tsx index edf2d7a4bc..ba0b29616a 100644 --- a/app/routes/company/components/CompaniesPage.tsx +++ b/app/routes/company/components/CompaniesPage.tsx @@ -21,7 +21,6 @@ import { selectAllPaginatedCompanies } from 'app/reducers/companies'; import { selectPaginationNext } from 'app/reducers/selectors'; import { useAppDispatch, useAppSelector } from 'app/store/hooks'; import { EntityType } from 'app/store/models/entities'; -import utilities from 'app/styles/utilities.css'; import useQuery from 'app/utils/useQuery'; import styles from './CompaniesPage.module.css'; import type { ListCompany } from 'app/store/models/Company'; @@ -188,36 +187,39 @@ const CompaniesPage = () => { Vis mer )} -
-

- Trykk deg inn på en bedrift for å se hva slags type bedrift det er, - les mer om hva de jobber med og se hvor de holder til. Bla deg - gjennom en oversikt over tidligere eller kommende arrangementer og - se hvem som har jobbannonser ute for øyeblikket. Hvis du vil lese - mer om bedriften så kan du navigere deg til nettsiden deres via - linken. -

- -

- Savner du en bedrift? Savner du noe informasjon om en bedrift? Ta - kontakt med Bedkom, vi tar gjerne imot innspill! -

- -
+ {expanded && ( +
+

+ Trykk deg inn på en bedrift for å se hva slags type bedrift det + er, les mer om hva de jobber med og se hvor de holder til. Bla deg + les mer om hva de jobber med og se hvor de holder til. Bla deg + gjennom en oversikt over tidligere eller kommende arrangementer og + se hvem som har jobbannonser ute for øyeblikket. Hvis du vil lese + mer om bedriften så kan du navigere deg til nettsiden deres via + linken. +

+ +

+ Savner du en bedrift? Savner du noe informasjon om en bedrift? Ta + kontakt med Bedkom, vi tar gjerne imot innspill! +

+ +
+ )} - + Aktive jobbannonser - + Kommende arrangementer From 95b16b917846c0586fc723b86f2d0009b00ce8bd Mon Sep 17 00:00:00 2001 From: Ivar Nakken Date: Wed, 18 Dec 2024 21:38:49 +0100 Subject: [PATCH 8/8] Refactor bdb page and company interest list to use a shared wrapper Same page component and tabs --- app/routes/bdb/components/BdbPage.tsx | 16 ++---- .../components/CompanyInterestList.tsx | 14 +---- app/routes/bdb/index.tsx | 51 ++++++++++++++++++- app/routes/bdb/utils.tsx | 10 ---- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/app/routes/bdb/components/BdbPage.tsx b/app/routes/bdb/components/BdbPage.tsx index 8fe240f629..56cbb6f14a 100644 --- a/app/routes/bdb/components/BdbPage.tsx +++ b/app/routes/bdb/components/BdbPage.tsx @@ -1,7 +1,6 @@ -import { Card, Flex, LinkButton, Page } from '@webkom/lego-bricks'; +import { Card, Flex } from '@webkom/lego-bricks'; import { usePreparedEffect } from '@webkom/react-prepare'; import { useMemo } from 'react'; -import { Helmet } from 'react-helmet-async'; import { Link } from 'react-router-dom'; import { fetchAllAdmin, fetchSemesters } from 'app/actions/CompanyActions'; import { SelectInput } from 'app/components/Form'; @@ -12,7 +11,6 @@ import { useAppDispatch, useAppSelector } from 'app/store/hooks'; import { guardLogin } from 'app/utils/replaceUnlessLoggedIn'; import useQuery from 'app/utils/useQuery'; import { - BdbTabs, getClosestCompanySemester, getCompanySemesterBySlug, getSemesterSlugById, @@ -139,16 +137,8 @@ const BdbPage = () => { }, ]; - const title = 'Bedriftsdatabase'; - return ( - Ny bedrift
} - tabs={} - > - - + <> Tips Du kan endre semesterstatuser ved å trykke på dem i listen! @@ -195,7 +185,7 @@ const BdbPage = () => { loading={fetching} hasMore={false} /> -
+ ); }; diff --git a/app/routes/bdb/components/companyInterest/components/CompanyInterestList.tsx b/app/routes/bdb/components/companyInterest/components/CompanyInterestList.tsx index f679298b64..cd3a393459 100644 --- a/app/routes/bdb/components/companyInterest/components/CompanyInterestList.tsx +++ b/app/routes/bdb/components/companyInterest/components/CompanyInterestList.tsx @@ -4,7 +4,6 @@ import { Flex, Icon, LinkButton, - Page, } from '@webkom/lego-bricks'; import { usePreparedEffect } from '@webkom/react-prepare'; import { FileDown, Trash2 } from 'lucide-react'; @@ -22,7 +21,6 @@ import { selectCompanyInterests } from 'app/reducers/companyInterest'; import { selectAllCompanySemesters } from 'app/reducers/companySemesters'; import { selectPaginationNext } from 'app/reducers/selectors'; import { - BdbTabs, getClosestCompanySemester, getCompanySemesterBySlug, getSemesterSlugById, @@ -228,15 +226,7 @@ const CompanyInterestList = () => { }); return ( - - Ny bedriftsinteresse - - } - tabs={} - > + <>

Her finner du all praktisk informasjon knyttet til bedriftsinteresser @@ -332,7 +322,7 @@ const CompanyInterestList = () => { data={companyInterestList} /> - + ); }; diff --git a/app/routes/bdb/index.tsx b/app/routes/bdb/index.tsx index bbe75e09e2..f2bde30898 100644 --- a/app/routes/bdb/index.tsx +++ b/app/routes/bdb/index.tsx @@ -1,6 +1,9 @@ import loadable from '@loadable/component'; +import { LinkButton, Page } from '@webkom/lego-bricks'; +import { Helmet } from 'react-helmet-async'; +import { Outlet, useLocation, type RouteObject } from 'react-router-dom'; +import { NavigationTab } from 'app/components/NavigationTab/NavigationTab'; import pageNotFound from '../pageNotFound'; -import type { RouteObject } from 'react-router-dom'; const BdbPage = loadable(() => import('./components/BdbPage')); const CompanyEditor = loadable(() => import('./components/CompanyEditor')); @@ -19,8 +22,52 @@ const CompanySemesterGUI = loadable( () => import('./components/companyInterest/components/CompanySemesterGUI'), ); +const BdbOverview = () => { + const isCompanyInterest = useLocation().pathname.includes('company-interest'); + + return ( + + Ny bedriftsinteresse + + ) : ( + + Ny bedrift + + ) + } + tabs={ + <> + Semesterstatuser + + Bedriftsinteresser + + + } + > + + + + ); +}; + const bdbRoute: RouteObject[] = [ - { index: true, Component: BdbPage }, + { + path: '', + Component: BdbOverview, + children: [ + { index: true, Component: BdbPage }, + { path: 'company-interest', Component: CompanyInterestList }, + ], + }, { path: 'add', Component: CompanyEditor }, { path: ':companyId', Component: BdbDetail }, { path: ':companyId/edit', Component: CompanyEditor }, diff --git a/app/routes/bdb/utils.tsx b/app/routes/bdb/utils.tsx index add8b3d92c..a135b3dba1 100644 --- a/app/routes/bdb/utils.tsx +++ b/app/routes/bdb/utils.tsx @@ -1,5 +1,4 @@ import moment from 'moment'; -import { NavigationTab } from 'app/components/NavigationTab/NavigationTab'; import { EventTypeConfig, colorForEventType } from 'app/routes/events/utils'; import { NonEventContactStatus } from 'app/store/models/Company'; import { EventType } from 'app/store/models/Event'; @@ -233,12 +232,3 @@ export const getContactStatuses = ( return Array.from(statuses); }; - -export const BdbTabs = () => ( - <> - Semesterstatuser - - Bedriftsinteresser - - -);