Skip to content

Commit

Permalink
various fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mruwnik committed Apr 30, 2024
1 parent 08e02dc commit 97ab76b
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 31 deletions.
4 changes: 2 additions & 2 deletions app/components/Article/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const ArticleFooter = (question: Question) => {
<Button
className="secondary"
action={question.answerEditLink || ''}
tooltip="Edit article"
tooltip="Suggest changes in Google Docs"
props={{target: '_blank', rel: 'noopener noreferrer'}}
>
<EditIcon className="no-fill" />
Expand Down Expand Up @@ -107,7 +107,7 @@ const ArticleActions = ({answerEditLink}: Question) => {
<Button
className="secondary"
action={answerEditLink || ''}
tooltip="Edit article"
tooltip="Suggest changes in Google Docs"
props={{target: '_blank', rel: 'noopener noreferrer'}}
>
<EditIcon className="no-fill" />
Expand Down
20 changes: 16 additions & 4 deletions app/hooks/useCachedObjects.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {useEffect, useState, createContext, useContext, ReactElement} from 'react'
import type {Tag, Glossary} from '~/server-utils/stampy'
import type {Tag, Glossary, Question} from '~/server-utils/stampy'
import {fetchTags} from '~/routes/categories.all'
import {fetchTOC, TOCItem} from '~/routes/questions.toc'
import {fetchGlossary} from '~/routes/questions.glossary'
import {fetchAllQuestionsOnSite} from '~/routes/questions.allQuestionsOnSite'

type ServerObject = Tag[] | TOCItem[] | Glossary
type APICall = () => Promise<Tag[] | TOCItem[] | Glossary>
type ServerObject = Tag[] | TOCItem[] | Glossary | Question[]
type APICall = () => Promise<ServerObject>
type useObjectsType<T extends ServerObject> = {
items?: T
}
Expand All @@ -25,23 +26,26 @@ export const useItemsFuncs = <T extends ServerObject>(apiFetcher: APICall): useO
}

type useCachedObjectsType = {
onSiteQuestions: useObjectsType<Question[]>
glossary: useObjectsType<Glossary>
tags: useObjectsType<Tag[]>
toc: useObjectsType<TOCItem[]>
}
export const CachedObjectsContext = createContext<useCachedObjectsType | null>(null)

const getOnSiteQuestions = async () => (await fetchAllQuestionsOnSite()).data
const getGlossary = async () => (await fetchGlossary()).data
const getTags = async () => (await fetchTags()).tags
const getToC = async () => (await fetchTOC()).data

export const CachedObjectsProvider = ({children}: {children: ReactElement}) => {
const onSiteQuestions = useItemsFuncs<Question[]>(getOnSiteQuestions)
const glossary = useItemsFuncs<Glossary>(getGlossary)
const tags = useItemsFuncs<Tag[]>(getTags)
const toc = useItemsFuncs<TOCItem[]>(getToC)

return (
<CachedObjectsContext.Provider value={{tags, glossary, toc}}>
<CachedObjectsContext.Provider value={{tags, glossary, toc, onSiteQuestions}}>
{children}
</CachedObjectsContext.Provider>
)
Expand All @@ -55,6 +59,14 @@ export const useCachedObjects = () => {
return context
}

export const useOnSiteQuestions = () => {
const context = useContext(CachedObjectsContext)
if (!context) {
throw new Error('useOnSiteQuestions must be used within a CachedObjectsProvider')
}
return context.onSiteQuestions
}

export const useTags = () => {
const context = useContext(CachedObjectsContext)
if (!context) {
Expand Down
55 changes: 32 additions & 23 deletions app/routes/questions.$questionId.$.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import Error from '~/components/Error'
import XIcon from '~/components/icons-generated/X'
import ChevronRight from '~/components/icons-generated/ChevronRight'
import {ArticlesNav} from '~/components/ArticlesNav/ArticleNav'
import {fetchGlossary} from '~/routes/questions.glossary'
import {loadQuestionDetail, loadTags} from '~/server-utils/stampy'
import {QuestionStatus, loadQuestionDetail} from '~/server-utils/stampy'
import useToC from '~/hooks/useToC'
import type {Question, Glossary, Tag} from '~/server-utils/stampy'
import useGlossary from '~/hooks/useGlossary'
import type {Question, Tag} from '~/server-utils/stampy'
import {reloadInBackgroundIfNeeded} from '~/server-utils/kv-cache'
import {useOnSiteQuestions, useTags} from '~/hooks/useCachedObjects'

export const LINK_WITHOUT_DETAILS_CLS = 'link-without-details'

Expand All @@ -27,11 +28,7 @@ export const loader = async ({request, params}: LoaderFunctionArgs) => {

try {
const dataPromise = loadQuestionDetail(request, questionId).catch(raise500)
const tagsPromise = loadTags(request)
.then(({data}) => data)
.catch(raise500)

return defer({question: dataPromise, tags: tagsPromise})
return defer({question: dataPromise})
} catch (error: unknown) {
console.log(error)
const msg = `No question found with ID ${questionId}. Please go to <a href="https://discord.com/invite/Bt8PaRTDQC">Discord</a> and report where you found this link.`
Expand All @@ -46,8 +43,8 @@ const dummyQuestion = (title: string | undefined) =>
tags: [],
}) as any as Question

const updateTags = (question: Question, tags: Tag[]) => {
const mappedTags = tags.reduce((acc, t) => ({...acc, [t.name]: t}), {})
const updateTags = (question: Question, tags?: Tag[]) => {
const mappedTags = tags?.reduce((acc, t) => ({...acc, [t.name]: t}), {}) || {}
return {
...question,
tags: question.tags
Expand All @@ -57,24 +54,32 @@ const updateTags = (question: Question, tags: Tag[]) => {
}
}

const updateRelated = (question: Question, allQuestions?: Question[]) => {
const live =
allQuestions
?.filter(({status}) => status === QuestionStatus.LIVE_ON_SITE)
.map(({pageid}) => pageid) || []
return {
...question,
relatedQuestions: question.relatedQuestions.filter(({pageid}) => live.includes(pageid)),
}
}

const updateFields = (question: Question, tags?: Tag[], allQuestions?: Question[]) =>
updateTags(updateRelated(question, allQuestions), tags)

export default function RenderArticle() {
const location = useLocation()
const [glossary, setGlossary] = useState<Glossary>({} as Glossary)
const [showNav, setShowNav] = useState(false) // Used on mobile
const params = useParams()
const {items: onSiteQuestions} = useOnSiteQuestions()
const {items: tags} = useTags()
const glossary = useGlossary()
const pageid = params.questionId ?? '😱'
const {question, tags} = useLoaderData<typeof loader>()
const {question} = useLoaderData<typeof loader>()
const {toc, findSection, getArticle, getPath} = useToC()
const section = findSection(location?.state?.section || pageid)

useEffect(() => {
const getGlossary = async () => {
const {data} = await fetchGlossary()
setGlossary(data)
}
getGlossary()
}, [setGlossary])

useEffect(() => {
setShowNav(false)
}, [location.key])
Expand Down Expand Up @@ -134,8 +139,8 @@ export default function RenderArticle() {
/>
}
>
<Await resolve={Promise.all([question, tags])}>
{([resolvedQuestion, resolvedTags]) => {
<Await resolve={question}>
{(resolvedQuestion) => {
if (resolvedQuestion instanceof Response || !('data' in resolvedQuestion)) {
return <Error error={resolvedQuestion} />
} else if (!resolvedQuestion.data.pageid) {
Expand All @@ -145,7 +150,11 @@ export default function RenderArticle() {
} else {
return (
<Article
question={updateTags(resolvedQuestion.data as Question, resolvedTags as Tag[])}
question={updateFields(
resolvedQuestion.data as Question,
tags,
onSiteQuestions
)}
glossary={glossary}
className={showNav ? 'desktop-only' : ''}
/>
Expand Down
2 changes: 1 addition & 1 deletion app/server-utils/parsing-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,5 @@ export const allLinksOnNewTab = (html: string): string => {
// Open external links on new tab by using target="_blank",
// pros&cons were extensively discussed in https://github.com/StampyAI/stampy-ui/issues/222
// internal links look like <a href="/?state=1234">, so all absolute http links are treated as external
return html.replace(/(<a href="[^"]+")/g, `$1 target="_blank" rel="noreferrer"`)
return html.replace(/(<a href="[^#].*?")/g, `$1 target="_blank" rel="noreferrer"`)
}
7 changes: 6 additions & 1 deletion stories/ArticlesKeepGoing.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,12 @@ const relatedQuestions = [
const withMockedToC = (StoryFn: any) => {
return (
<CachedObjectsContext.Provider
value={{toc: {items: toc}, glossary: {items: undefined}, tags: {items: undefined}}}
value={{
toc: {items: toc},
glossary: {items: undefined},
tags: {items: undefined},
onSiteQuestions: {items: undefined},
}}
>
<StoryFn />
</CachedObjectsContext.Provider>
Expand Down

0 comments on commit 97ab76b

Please sign in to comment.