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

Public faq frontend + some API adjustment #70

Merged
merged 3 commits into from
Dec 11, 2023
Merged
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
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ VITE_FIREBASE_OPEN_PLANNER_DOMAIN=
VITE_FIREBASE_OPEN_PLANNER_STORAGE_BUCKET=
VITE_FIREBASE_OPEN_PLANNER_APP_ID=
VITE_FIREBASE_OPEN_PLANNER_MEASUREMENT_ID=
VITE_FIREBASE_OPEN_PLANNER_API_URL=https://example.com
45 changes: 45 additions & 0 deletions functions/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"main": "lib/index.js",
"dependencies": {
"@fastify/auth": "^4.4.0",
"@fastify/cors": "^8.4.2",
"@fastify/swagger": "^8.12.0",
"@fastify/swagger-ui": "^1.10.1",
"@fastify/type-provider-typebox": "^3.5.0",
Expand Down
8 changes: 7 additions & 1 deletion functions/src/api/dao/faqDao.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ export class FaqDao {
throw new NotFoundError('FAQ category does not exist or no items found')
}

return snapshot.docs.map((doc) => doc.data() as FaqType)
return snapshot.docs.map(
(doc) =>
({
...doc.data(),
id: doc.id,
} as FaqType)
)
}
}
6 changes: 6 additions & 0 deletions functions/src/api/faq/faq.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FastifyInstance } from 'fastify'
import { Static, Type } from '@sinclair/typebox'
import { FaqDao } from '../dao/faqDao'
import { EventDao } from '../dao/eventDao'

const FaqCategory = Type.Object({
id: Type.String(),
Expand All @@ -13,6 +14,7 @@ const FaqCategory = Type.Object({
export type FaqCategoryType = Static<typeof FaqCategory>

export const Faq = Type.Object({
id: Type.String(),
categoryId: Type.String(),
categoryName: Type.Optional(Type.String()),
question: Type.String(),
Expand All @@ -27,6 +29,7 @@ const Reply = Type.Object({ faqItemId: Type.String() })
type FaqReply = Static<typeof Reply>

const GetReply = Type.Object({
eventName: Type.String(),
faq: Type.Array(
Type.Object({
category: FaqCategory,
Expand Down Expand Up @@ -86,6 +89,7 @@ export const faqRoutes = (fastify: FastifyInstance, options: any, done: () => an

const output = []

const event = await EventDao.getEvent(fastify.firebase, eventId)
const faqCategories = await FaqDao.getFaqPrivateCategory(fastify.firebase, eventId, faqPrivateId)

for (const faqCategory of faqCategories) {
Expand All @@ -94,6 +98,7 @@ export const faqRoutes = (fastify: FastifyInstance, options: any, done: () => an
const questionsWithCategoryInfo: FaqType[] = questions.map((question) => {
return {
...question,
id: question.id,
categoryId: faqCategory.id,
categoryName: faqCategory.name,
categoryOrder: faqCategory.order,
Expand All @@ -107,6 +112,7 @@ export const faqRoutes = (fastify: FastifyInstance, options: any, done: () => an
}

reply.status(200).send({
eventName: event.name,
faq: output,
})
}
Expand Down
4 changes: 4 additions & 0 deletions functions/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { fastifyAuth, FastifyAuthFunction } from '@fastify/auth'
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import { registerSwagger } from './swagger'
import { app as firebaseApp } from 'firebase-admin'
import cors from '@fastify/cors'
import { firebasePlugin } from './dao/firebasePlugin'

import { fastifyErrorHandler } from './other/fastifyErrorHandler'
Expand Down Expand Up @@ -38,6 +39,9 @@ if (!isNodeEnvDev) {
fastify.register(fastifyAuth)
fastify.register(firebasePlugin)
fastify.register(apiKeyPlugin)
fastify.register(cors, {
origin: '*',
})
registerSwagger(fastify)

fastify.register(sponsorsRoutes)
Expand Down
34 changes: 20 additions & 14 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { LinkProps } from '@mui/material/Link'
import { EventRouter } from './events/page/EventRouter'
import { NotificationProvider } from './context/SnackBarProvider'
import { SuspenseLoader } from './components/SuspenseLoader'
import { PublicApp } from './public/PublicApp'

const EventsScreen = lazy(() =>
import('./events/list/EventsScreen').then((module) => ({ default: module.EventsScreen }))
Expand Down Expand Up @@ -59,20 +60,25 @@ export const App = ({}) => {
<ThemeProvider theme={theme}>
<CssBaseline enableColorScheme />
<NotificationProvider>
<RequireLogin>
<Switch>
<Route path="/">
<Suspense fallback={<SuspenseLoader />}>
<EventsScreen />
</Suspense>
</Route>
<Route path="/events/">
<Redirect to="/" />
</Route>
<EventRouter />
<Route>404, Not Found!</Route>
</Switch>
</RequireLogin>
<Switch>
<Route path="/public/event/:eventId/:page*">
<PublicApp />
</Route>
<RequireLogin>
<Switch>
<Route path="/">
<Suspense fallback={<SuspenseLoader />}>
<EventsScreen />
</Suspense>
</Route>
<Route path="/events/">
<Redirect to="/" />
</Route>
<EventRouter />
<Route>404, Not Found!</Route>
</Switch>
</RequireLogin>
</Switch>
</NotificationProvider>
</ThemeProvider>
</Provider>
Expand Down
6 changes: 5 additions & 1 deletion src/events/page/faq/FaqCategoryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ export type FaqCategoryProps = {
}

const getFaqCategoryPrivateLink = (event: Event, publicCategoryId: string) => {
return `https://openplanner.fr/public/event/${event.id}/faq/${publicCategoryId}`
const port = window.location.port
const domainName = window.location.hostname + (port ? `:${port}` : '')
const protocol = window.location.protocol

return `${protocol}//${domainName}/public/event/${event.id}/faq/${publicCategoryId}`
}

export const FaqCategoryItem = (props: FaqCategoryProps) => {
Expand Down
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
}
6 changes: 6 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
.session-card-rnd:hover {
z-index: 10 !important;
}

/* For PUBLIC FAQ MARKDOWN */
.wmde-markdown-color {
background: inherit !important;
font-family: inherit !important;
}
46 changes: 46 additions & 0 deletions src/public/PublicApp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from 'react'
import { useEffect } from 'react'
import { Route, Switch, useRoute } from 'wouter'
import { NestedRoutes } from '../components/NestedRoutes'
import { usePublicEvent } from './hooks/usePublicEvent'
import { PublicEventFaq } from './faq/PublicEventFaq'
import { FirestoreQueryLoaderAndErrorDisplay } from '../components/FirestoreQueryLoaderAndErrorDisplay'
import { Typography } from '@mui/material'

export type PublicAppProps = {}
export const PublicApp = (props: PublicAppProps) => {
const [_, params] = useRoute('/public/event/:eventId/:subRoute/:privateId*')

const publicEvent = usePublicEvent(params?.eventId, params?.privateId)

useEffect(() => {
document.title = `FAQ | ${publicEvent.data ? publicEvent.data.eventName : ''}`
}, [params])

if (publicEvent.isLoading) {
return <FirestoreQueryLoaderAndErrorDisplay hookResult={publicEvent} />
}

if (!publicEvent.data) {
return <>Error? {JSON.stringify(publicEvent, null, 4)}</>
}

const publicEventData = publicEvent.data

return (
<NestedRoutes base={`/public/event/${params?.eventId}`}>
<Switch>
<Route path="/faq">
<PublicEventFaq faqReply={publicEventData} />
</Route>
<Route path="/faq/:privateId">
<PublicEventFaq faqReply={publicEventData} />
</Route>

<Route>
<Typography variant="h1">Not implemented!</Typography>
</Route>
</Switch>
</NestedRoutes>
)
}
Loading