Skip to content

Commit

Permalink
Add queryparams for open category and question
Browse files Browse the repository at this point in the history
  • Loading branch information
HugoGresse committed Dec 11, 2023
1 parent b70aaac commit 83e3faf
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 8 deletions.
89 changes: 89 additions & 0 deletions src/hooks/useSearchParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { useCallback, useMemo, useRef } from 'react'
import { navigate, useSearch } from 'wouter/use-location'

// Based on react-router: https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx

/**
* Copied from https://github.com/molefrog/wouter/issues/368#issuecomment-1807545003
* Thank you!
*/

type ParamKeyValuePair = [string, string]

type URLSearchParamsInit = string | ParamKeyValuePair[] | Record<string, string | string[]> | URLSearchParams

export function createSearchParams(init: URLSearchParamsInit = ''): URLSearchParams {
return new URLSearchParams(
typeof init === 'string' || Array.isArray(init) || init instanceof URLSearchParams
? init
: Object.keys(init).reduce((memo, key) => {
const value = init[key]
return memo.concat(Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]])
}, [] as ParamKeyValuePair[])
)
}

export function getSearchParamsForLocation(locationSearch: string, defaultSearchParams: URLSearchParams | null) {
const searchParams = createSearchParams(locationSearch)

if (defaultSearchParams) {
// Use `defaultSearchParams.forEach(...)` here instead of iterating of
// `defaultSearchParams.keys()` to work-around a bug in Firefox related to
// web extensions. Relevant Bugzilla tickets:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1414602
// https://bugzilla.mozilla.org/show_bug.cgi?id=1023984
defaultSearchParams.forEach((_, key) => {
if (!searchParams.has(key)) {
defaultSearchParams.getAll(key).forEach((value) => {
searchParams.append(key, value)
})
}
})
}

return searchParams
}

export function useSearchParams(defaultInit?: URLSearchParamsInit) {
if (typeof URLSearchParams === 'undefined') {
console.warn(
`You cannot use the \`useSearchParams\` hook in a browser that does not ` +
`support the URLSearchParams API. If you need to support Internet ` +
`Explorer 11, we recommend you load a polyfill such as ` +
`https://github.com/ungap/url-search-params\n\n` +
`If you're unsure how to load polyfills, we recommend you check out ` +
`https://polyfill.io/v3/ which provides some recommendations about how ` +
`to load polyfills only for users that need them, instead of for every ` +
`user.`
)
}

const defaultSearchParamsRef = useRef(createSearchParams(defaultInit))
const hasSetSearchParamsRef = useRef(false)

const search = useSearch()
const searchParams = useMemo(
() =>
// Only merge in the defaults if we haven't yet called setSearchParams.
// Once we call that we want those to take precedence, otherwise you can't
// remove a param with setSearchParams({}) if it has an initial value
getSearchParamsForLocation(search, hasSetSearchParamsRef.current ? null : defaultSearchParamsRef.current),
[search]
)

const setSearchParams = useCallback(
(
nextInit: URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit),
navigateOpts?: Parameters<typeof navigate>['1']
) => {
const newSearchParams = createSearchParams(
typeof nextInit === 'function' ? nextInit(searchParams) : nextInit
)
hasSetSearchParamsRef.current = true
navigate('?' + newSearchParams, navigateOpts)
},
[searchParams]
)

return [searchParams, setSearchParams] as const
}
18 changes: 16 additions & 2 deletions src/public/faq/PublicEventFaq.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@ import { PublicFaqReply } from '../publicTypes'
import { PublicEventLayout } from '../PublicEventLayout'
import { PublicFaqCategory } from './PublicFaqCategory'
import { PublicFaqCategoryPicker } from './PublicFaqCategoryPicker'
import { useSearchParams } from '../../hooks/useSearchParams'

export type PublicEventFaqProps = {
faqReply: PublicFaqReply
}
export const PublicEventFaq = ({ faqReply }: PublicEventFaqProps) => {
const hasMoreThanOneCategory = faqReply.faq.length > 1
const [searchParams, setSearchParams] = useSearchParams()
const [selectedCategoryId, setSelectedCategory] = useState<string | null>(
hasMoreThanOneCategory ? null : faqReply.faq[0].category.id
hasMoreThanOneCategory
? searchParams.get('category')
? searchParams.get('category')
: null
: faqReply.faq[0].category.id
)

const selectedCategory = selectedCategoryId
Expand All @@ -38,7 +44,15 @@ export const PublicEventFaq = ({ faqReply }: PublicEventFaqProps) => {
<PublicFaqCategoryPicker
faqReply={faqReply}
selectedCategoryId={selectedCategoryId}
onSelectCategory={setSelectedCategory}
onSelectCategory={(categoryId) => {
if (categoryId === selectedCategoryId) {
setSelectedCategory(null)
setSearchParams({})
return
}
setSelectedCategory(categoryId)
setSearchParams({ category: categoryId })
}}
/>
) : null}

Expand Down
16 changes: 15 additions & 1 deletion src/public/faq/PublicFaqCategory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import * as React from 'react'
import { PublicFaqType } from '../publicTypes'
import { Box, Typography } from '@mui/material'
import { FaqQuestion } from './FaqQuestion'
import { useSearchParams } from '../../hooks/useSearchParams'

export type FaqCategoryProps = {
faq: PublicFaqType
}
export const PublicFaqCategory = ({ faq }: FaqCategoryProps) => {
const [openQuestionId, setOpenQuestion] = React.useState<string | null>(null)
const [searchParams, setSearchParams] = useSearchParams()
const [openQuestionId, setOpenQuestion] = React.useState<string | null>(
searchParams.get('question') ? searchParams.get('question') : null
)

if (faq.questions.length === 0) {
return (
Expand All @@ -33,9 +37,19 @@ export const PublicFaqCategory = ({ faq }: FaqCategoryProps) => {
open={openQuestionId === question.id}
onClick={() => {
if (openQuestionId === question.id) {
setSearchParams((prev) => {
const newParams = new URLSearchParams(prev)
newParams.delete('question')
return newParams
})
setOpenQuestion(null)
return
}
setSearchParams((prev) => {
const newParams = new URLSearchParams(prev)
newParams.set('question', question.id)
return newParams
})
setOpenQuestion(question.id)
}}
/>
Expand Down
6 changes: 1 addition & 5 deletions src/public/faq/PublicFaqCategoryPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { PublicFaqReply } from '../publicTypes'
export type PublicFaqCategoryPickerProps = {
faqReply: PublicFaqReply
selectedCategoryId: string | null
onSelectCategory: (categoryId: string | null) => void
onSelectCategory: (categoryId: string) => void
}
export const PublicFaqCategoryPicker = ({
faqReply,
Expand All @@ -23,10 +23,6 @@ export const PublicFaqCategoryPicker = ({
variant="contained"
endIcon={selectedCategoryId === faq.category.id ? <ExpandLess /> : <ExpandMore />}
onClick={() => {
if (selectedCategoryId === faq.category.id) {
onSelectCategory(null)
return
}
onSelectCategory(faq.category.id)
}}>
<Typography variant="h6">{faq.category.name}</Typography>
Expand Down

0 comments on commit 83e3faf

Please sign in to comment.