Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1319 Add Contacts search section #1327

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions next/components/sections/ContactsSearchSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react'

import GlobalSearchSectionContent from '@/components/sections/SearchSection/GlobalSearchSectionContent'

const ContactsSearchSection = () => {
return <GlobalSearchSectionContent variant="specific" searchOption="users" pageSize={6} />
}

export default ContactsSearchSection
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ type Props =
| {
variant: 'general'
searchOption?: never
pageSize?: never
}
| {
variant: 'specific'
searchOption: Exclude<SearchOption['id'], 'allResults'>
pageSize?: number
}

const GlobalSearchSectionContent = ({ variant, searchOption }: Props) => {
const GlobalSearchSectionContent = ({ variant, searchOption, pageSize = 12 }: Props) => {
const { t } = useTranslation()

const [routerQueryValue] = useQueryParam('keyword', withDefault(StringParam, ''))
Expand Down Expand Up @@ -180,7 +182,7 @@ const GlobalSearchSectionContent = ({ variant, searchOption }: Props) => {
const searchFilters: SearchFilters = {
search: searchValue,
page: currentPage,
pageSize: 12,
pageSize,
// tagIds need to be here for now, because BlogPost and InbaArticle fetchers filter by tagIds
tagIds: [],
// Official board category id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ export const useQueryBySearchOption = ({
})

const usersQuery = useQuery({
queryKey: getMsGraphSearchQueryKey(filters.search),
queryFn: () => msGraphSearchFetcher(filters.search),
queryKey: getMsGraphSearchQueryKey(filters.search, filters.pageSize),
queryFn: () => msGraphSearchFetcher(filters.search, filters.pageSize),
placeholderData: keepPreviousData,
select: (axiosResponse) => {
const formattedData: SearchResult[] =
Expand Down
5 changes: 3 additions & 2 deletions next/pages/api/ms-graph/search-in-structure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import { MSGraphFilteredGroupUser } from '@/services/ms-graph/types'
// TODO error types

const handler = async (req: NextApiRequest, res: NextApiResponse<MSGraphFilteredGroupUser[]>) => {
const { query: queryParam } = req.query
const { query: queryParam, pageSize: pageSizeParam } = req.query

const query = typeof queryParam === 'string' ? queryParam : queryParam?.[0]
const pageSize = typeof pageSizeParam === 'string' ? parseInt(pageSizeParam, 10) : undefined

if (!query) {
res.status(200).json([])
Expand All @@ -19,7 +20,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse<MSGraphFiltered
try {
const { accessToken } = (await getMsalToken()) ?? {}

const users = await searchInOrgStructure(query, accessToken ?? '')
const users = await searchInOrgStructure(accessToken ?? '', query, pageSize)

res.status(200).json(users)
} catch (error) {
Expand Down
11 changes: 8 additions & 3 deletions next/services/ms-graph/fetchers/msGraphSearch.fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import axios from 'axios'

import { MSGraphFilteredGroupUser } from '@/services/ms-graph/types'

export const getMsGraphSearchQueryKey = (search: string) => ['Search', 'msGraphSearch', search]
export const getMsGraphSearchQueryKey = (search: string, pageSize: number) => [
'Search',
'msGraphSearch',
search,
pageSize,
]

export const msGraphSearchFetcher = async (searchQuery: string) => {
export const msGraphSearchFetcher = async (searchQuery: string, pageSize: number) => {
return axios.get<MSGraphFilteredGroupUser[]>(
`/api/ms-graph/search-in-structure?query=${searchQuery}`,
`/api/ms-graph/search-in-structure?query=${searchQuery}&pageSize=${pageSize}`,
)
}
14 changes: 11 additions & 3 deletions next/services/ms-graph/server/searchInOrgStructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,27 @@ import { MSGraphFilteredGroupUser } from '@/services/ms-graph/types'
* https://learn.microsoft.com/en-us/graph/search-query-parameter?tabs=http#using-search-on-directory-object-collections
* https://learn.microsoft.com/en-us/graph/best-practices-concept
*
* @param query
* @param accessToken
* @param query
* @param pageSize
*/
export const searchInOrgStructure = async (query: string, accessToken: string) => {
export const searchInOrgStructure = async (
accessToken: string,
query: string,
pageSize?: number,
) => {
/* Letters with diacritics causes request to fail (it needs investigation why, but slugify helps) */
const sanitizedQuery = slugify(query, { separator: ' ', customReplacements: [['ä', 'a']] }).trim()

const url = `https://graph.microsoft.com/v1.0/groups/${MS_GRAPH_GROUP_ID}/transitiveMembers?${[
`$select=${PARAMS_FROM_MS_GRAPH_API.join(',')}`,
`$search="displayName:${sanitizedQuery}" OR "jobTitle:${sanitizedQuery}" OR "mail:${sanitizedQuery}"`,
pageSize ? `$top=${pageSize}` : '',
// TODO add support for searching in businessPhones and mobilePhone
// `$filter=businessPhones/any(p:startsWith(p, '+421-'))`,
].join('&')}`
]
.filter(Boolean)
.join('&')}`

const response = await axios.get<{ value: MSGraphFilteredGroupUser[] }>(url, {
headers: {
Expand Down
Loading