diff --git a/app/actions/CompanyActions.ts b/app/actions/CompanyActions.ts index 0192c30a67..e606bd828f 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'; @@ -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/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); } 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/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/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/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/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 93% rename from app/routes/companyInterest/components/CompanyInterestList.tsx rename to app/routes/bdb/components/companyInterest/components/CompanyInterestList.tsx index 8885d78064..cd3a393459 100644 --- a/app/routes/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, @@ -46,6 +44,7 @@ type SemesterOptionType = { const defaultCompanyInterestsQuery = { semester: '', event: CompanyInterestEventType.All, + companyName: '', }; const CompanyInterestList = () => { @@ -53,13 +52,17 @@ 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 = ( slug: string | undefined, companySemesters: CompanySemester[], ) => { + if (slug === '') return null; + if (slug) { const companySemester = getCompanySemesterBySlug(slug, companySemesters); if (companySemester) return companySemester; @@ -115,10 +118,10 @@ const CompanyInterestList = () => { ), [query], ); + usePreparedEffect( 'fetchCompanyInterestListSemesters', () => dispatch(fetchSemesters()), - [], ); @@ -150,8 +153,10 @@ const CompanyInterestList = () => { { title: 'Bedriftsnavn', dataIndex: 'companyName', + search: true, + inlineFiltering: true, render: (companyName: string, companyInterest) => ( - + {companyInterest.company ? companyInterest.company.name : companyName} ), @@ -180,7 +185,12 @@ const CompanyInterestList = () => { }} > {({ openConfirmModal }) => ( - } danger /> + } + size={18} + danger + /> )} @@ -216,15 +226,7 @@ const CompanyInterestList = () => { }); return ( - - Ny bedriftsinteresse - - } - tabs={} - > + <>

Her finner du all praktisk informasjon knyttet til bedriftsinteresser @@ -257,7 +259,7 @@ const CompanyInterestList = () => { isClearable={false} /> - + Endre aktive semestre @@ -315,10 +317,12 @@ const CompanyInterestList = () => { }} hasMore={hasMore} loading={fetching} + filters={query} + onChange={setQuery} data={companyInterestList} /> - + ); }; 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..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')); @@ -9,9 +12,62 @@ 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 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 }, @@ -21,6 +77,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..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,10 +232,3 @@ export const getContactStatuses = ( return Array.from(statuses); }; - -export const BdbTabs = () => ( - <> - Bedriftsinteresser - BDB - -); 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 35ce22cf8d..ba0b29616a 100644 --- a/app/routes/company/components/CompaniesPage.tsx +++ b/app/routes/company/components/CompaniesPage.tsx @@ -7,17 +7,21 @@ import { Image, Page, LinkButton, + filterSidebar, + FilterSection, } from '@webkom/lego-bricks'; import { usePreparedEffect } from '@webkom/react-prepare'; -import { useState } 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 { selectActiveCompanies } from 'app/reducers/companies'; +import { CheckBox, TextInput } from 'app/components/Form'; +import { selectAllPaginatedCompanies } from 'app/reducers/companies'; import { selectPaginationNext } from 'app/reducers/selectors'; import { useAppDispatch, useAppSelector } from 'app/store/hooks'; -import utilities from 'app/styles/utilities.css'; +import { EntityType } from 'app/store/models/entities'; +import useQuery from 'app/utils/useQuery'; import styles from './CompaniesPage.module.css'; import type { ListCompany } from 'app/store/models/Company'; @@ -84,31 +88,79 @@ const CompanyList = ({ companies = [] }: CompanyListProps) => ( ); +export const companiesDefaultQuery = { + search: '', + showInactive: 'false' as 'true' | 'false', +}; + const CompaniesPage = () => { const [expanded, setExpanded] = useState(false); + const [debouncedSearch, setDebouncedSearch] = useState(''); + const { query, setQueryValue } = useQuery(companiesDefaultQuery); - const companies = useAppSelector(selectActiveCompanies); const { pagination } = useAppSelector((state) => selectPaginationNext({ - query: {}, - entity: 'companies', + query: { ...query, search: debouncedSearch }, + entity: EntityType.Companies, endpoint: '/companies/', })(state), ); - const dispatch = useAppDispatch(); + 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 ( + + setQueryValue('search')(e.target.value)} + /> + + + setQueryValue('showInactive')( + query.showInactive === 'true' ? 'false' : 'true', + ) + } + /> + + ), + })} actionButtons={ (actionGrant.includes('create') || actionGrant.includes('edit')) && ( Bedriftsdatabasen @@ -135,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 @@ -176,7 +231,12 @@ const CompaniesPage = () => { loadMore={() => pagination.hasMore && !pagination.fetching && - dispatch(fetchAll({ fetchMore: true })) + dispatch( + fetchAll({ + fetchMore: true, + query: { ...query, search: debouncedSearch }, + }), + ) } initialLoad={false} loader={} 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 },