From 73af95fb7249a15019a5e22ff33faa70a897b62d Mon Sep 17 00:00:00 2001 From: Foysal Ahamed Date: Tue, 6 Feb 2024 20:25:24 +0100 Subject: [PATCH] :recycle: Refactor titles to useTitle hook --- app/communication-template/[id]/edit/page.tsx | 7 +- app/communication-template/create/page.tsx | 7 +- app/communication-template/page.tsx | 8 +-- app/events/[id]/page.tsx | 20 +++--- app/events/page-content.tsx | 6 +- app/reports/page-content.tsx | 69 ++++++++++++------- app/repositories/[id]/[...record]/page.tsx | 60 +++++++++------- app/repositories/[id]/page-content.tsx | 50 +++++++------- app/repositories/page-content.tsx | 15 ++-- app/subject-status/page.tsx | 13 ++-- app/surprise-me/page.tsx | 6 +- 11 files changed, 138 insertions(+), 123 deletions(-) diff --git a/app/communication-template/[id]/edit/page.tsx b/app/communication-template/[id]/edit/page.tsx index 621337dd..bd06f4e2 100644 --- a/app/communication-template/[id]/edit/page.tsx +++ b/app/communication-template/[id]/edit/page.tsx @@ -1,13 +1,10 @@ 'use client' +import { useTitle } from 'react-use' import { CommunicationTemplateForm } from 'components/communication-template/form' -import { useEffect } from 'react' export default function CommunicationTemplateEditPage({ params: { id } }) { - // Change page title dynamically - useEffect(() => { - document.title = `Edit Communication Templates #${id}` - }, [id]) + useTitle(`Edit Communication Templates #${id}`) return (
diff --git a/app/communication-template/create/page.tsx b/app/communication-template/create/page.tsx index 9408404a..2efeed2e 100644 --- a/app/communication-template/create/page.tsx +++ b/app/communication-template/create/page.tsx @@ -1,13 +1,10 @@ 'use client' +import { useTitle } from 'react-use' import { CommunicationTemplateForm } from 'components/communication-template/form' -import { useEffect } from 'react' export default function CommunicationTemplateCreatePage() { - // Change page title dynamically - useEffect(() => { - document.title = `Create Communication Templates` - }, []) + useTitle(`Create Communication Templates`) return (
diff --git a/app/communication-template/page.tsx b/app/communication-template/page.tsx index 4c999351..cc38a0f2 100644 --- a/app/communication-template/page.tsx +++ b/app/communication-template/page.tsx @@ -1,9 +1,10 @@ 'use client' import format from 'date-fns/format' -import { useEffect, useState } from 'react' +import { useState } from 'react' import Link from 'next/link' import { PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/20/solid' +import { useTitle } from 'react-use' import { LabelChip } from '@/common/labels' import { Loading, LoadingFailed } from '@/common/Loader' @@ -17,10 +18,7 @@ export default function CommunicationTemplatePage() { string | undefined >() - // Change page title dynamically - useEffect(() => { - document.title = `Communication Templates` - }, []) + useTitle(`Communication Templates`) if (isLoading) { return diff --git a/app/events/[id]/page.tsx b/app/events/[id]/page.tsx index d9ee124b..dbda8284 100644 --- a/app/events/[id]/page.tsx +++ b/app/events/[id]/page.tsx @@ -1,9 +1,9 @@ 'use client' import { useQuery } from '@tanstack/react-query' +import { useTitle } from 'react-use' import client from '@/lib/client' import { Loading, LoadingFailed } from '@/common/Loader' import { EventView } from '@/mod-event/View' -import { useEffect } from 'react' import { MOD_EVENT_TITLES } from '@/mod-event/constants' export default function EventViewPage({ params }: { params: { id: string } }) { @@ -19,17 +19,13 @@ export default function EventViewPage({ params }: { params: { id: string } }) { }, }) - // Change page title dynamically - // Use a human-readable event name once event details are fetched - useEffect(() => { - if (event) { - const eventTitle = - MOD_EVENT_TITLES[event.event.$type as string] || 'Moderation' - document.title = `${eventTitle} Event #${id}` - } else { - document.title = `Moderation Event #${id}` - } - }, [id, event]) + let pageTitle = `Moderation Event #${id}` + if (event) { + const eventTitle = + MOD_EVENT_TITLES[event.event.$type as string] || 'Moderation' + pageTitle = `${eventTitle} Event #${id}` + } + useTitle(pageTitle) if (error) { return diff --git a/app/events/page-content.tsx b/app/events/page-content.tsx index 7a2b5841..07f55904 100644 --- a/app/events/page-content.tsx +++ b/app/events/page-content.tsx @@ -1,9 +1,9 @@ +import { useTitle } from 'react-use' import { ModEventList } from '@/mod-event/EventList' import { emitEvent } from '@/mod-event/helpers/emitEvent' import { ComAtprotoAdminEmitModerationEvent } from '@atproto/api' import { ModActionPanelQuick } from 'app/actions/ModActionPanel/QuickAction' import { usePathname, useRouter, useSearchParams } from 'next/navigation' -import { useEffect } from 'react' export default function EventListPageContent() { const searchParams = useSearchParams() @@ -20,9 +20,7 @@ export default function EventListPageContent() { router.push((pathname ?? '') + '?' + newParams.toString()) } - useEffect(() => { - document.title = `Moderation Events` - }, []) + useTitle(`Moderation Events`) return (
diff --git a/app/reports/page-content.tsx b/app/reports/page-content.tsx index b19425ed..7161a7aa 100644 --- a/app/reports/page-content.tsx +++ b/app/reports/page-content.tsx @@ -22,6 +22,7 @@ import { AuthContext } from '@/shell/AuthContext' import { ButtonGroup } from '@/common/buttons' import { useFluentReportSearch } from '@/reports/useFluentReportSearch' import { SubjectTable } from 'components/subject/table' +import { useTitle } from 'react-use' const TABS = [ { @@ -48,6 +49,42 @@ const TABS = [ { key: 'all', name: 'All', href: '/reports' }, ] +const buildPageTitle = ({ + currentTab, + takendown, + includeMuted, + appealed, +}: { + currentTab: string + takendown: boolean + includeMuted: boolean + appealed: boolean +}) => { + const titleFromTab = + currentTab === 'all' + ? `All subjects` + : `${currentTab[0].toUpperCase()}${currentTab.slice(1)}` + const additionalFragments: string[] = [] + + if (takendown) { + additionalFragments.push('Taken Down') + } + + if (includeMuted) { + additionalFragments.push('Include Muted') + } + + if (appealed) { + additionalFragments.push('Appealed') + } + + const additionalTitle = additionalFragments.length + ? ` (${additionalFragments.join(', ')})` + : '' + const title = `Queue - ${titleFromTab}${additionalTitle}` + return title +} + const ResolvedFilters = () => { const router = useRouter() const pathname = usePathname() @@ -197,31 +234,13 @@ export const ReportsPageContent = () => { ), ) - useEffect(() => { - const titleFromTab = - currentTab === 'all' - ? `All subjects` - : `${currentTab[0].toUpperCase()}${currentTab.slice(1)}` - const additionalFragments: string[] = [] - - if (takendown) { - additionalFragments.push('Taken Down') - } - - if (includeMuted) { - additionalFragments.push('Include Muted') - } - - if (appealed) { - additionalFragments.push('Appealed') - } - - const additionalTitle = additionalFragments.length - ? ` (${additionalFragments.join(', ')})` - : '' - const title = `Queue - ${titleFromTab}${additionalTitle}` - document.title = title - }, [currentTab, takendown, includeMuted, appealed]) + const pageTitle = buildPageTitle({ + currentTab, + takendown, + includeMuted, + appealed, + }) + useTitle(pageTitle) return ( <> diff --git a/app/repositories/[id]/[...record]/page.tsx b/app/repositories/[id]/[...record]/page.tsx index 5769f180..ad81ea5a 100644 --- a/app/repositories/[id]/[...record]/page.tsx +++ b/app/repositories/[id]/[...record]/page.tsx @@ -15,6 +15,36 @@ import { usePathname, useRouter, useSearchParams } from 'next/navigation' import { ModActionPanelQuick } from 'app/actions/ModActionPanel/QuickAction' import { emitEvent } from '@/mod-event/helpers/emitEvent' import { useEffect } from 'react' +import { useTitle } from 'react-use' + +const buildPageTitle = ({ + handle, + collection, + rkey, +}: { + handle?: string + collection?: string + rkey?: string +}) => { + let title = `Record Details` + + if (collection) { + const titleFromCollection = collection.split('.').pop() + if (titleFromCollection) { + title = + titleFromCollection[0].toUpperCase() + titleFromCollection.slice(1) + } + } + + if (handle) { + title += ` - ${handle}` + } + + if (rkey) { + title += ` - ${rkey}` + } + return title +} export default function Record({ params, @@ -116,30 +146,12 @@ export default function Record({ } }, [data, reportUri]) - // Change title dynamically - // Show the collection name - // Once we retrieve the profile/repo details, show the handle - useEffect(() => { - let title = `Record Details` - - if (collection) { - const titleFromCollection = collection.split('.').pop() - if (titleFromCollection) { - title = - titleFromCollection[0].toUpperCase() + titleFromCollection.slice(1) - } - } - - if (data?.record?.repo) { - title += ` - ${data.record.repo.handle}` - } - - if (rkey) { - title += ` - ${rkey}` - } - - document.title = title - }, [data, collection]) + const pageTitle = buildPageTitle({ + handle: data?.record?.repo.handle, + rkey, + collection, + }) + useTitle(pageTitle) if (error) { return diff --git a/app/repositories/[id]/page-content.tsx b/app/repositories/[id]/page-content.tsx index 469d3c6e..2a8f29b2 100644 --- a/app/repositories/[id]/page-content.tsx +++ b/app/repositories/[id]/page-content.tsx @@ -6,8 +6,29 @@ import { ComAtprotoAdminEmitModerationEvent } from '@atproto/api' import { ModActionPanelQuick } from 'app/actions/ModActionPanel/QuickAction' import { usePathname, useRouter, useSearchParams } from 'next/navigation' import { emitEvent } from '@/mod-event/helpers/emitEvent' -import { useEffect } from 'react' +import { useTitle } from 'react-use' +const buildPageTitle = ({ + handle, + tab, +}: { + handle: string + tab: string | null +}) => { + let title = `Repository Details` + const titleFragments: string[] = [title] + const titleFromTab = tab ? tab[0].toUpperCase() + tab.slice(1) : '' + + if (titleFromTab) { + titleFragments.unshift(titleFromTab) + } + + if (handle) { + titleFragments.unshift(handle) + } + + return titleFragments.join(' - ') +} export function RepositoryViewPageContent({ id }: { id: string }) { const { error, @@ -30,28 +51,11 @@ export function RepositoryViewPageContent({ id }: { id: string }) { } const tab = searchParams.get('tab') - // Change title dynamically - // Once we retrieve the profile/repo details, show the handle - // Show the current tab name from account view - useEffect(() => { - let title = `Repository Details` - const titleFragments: string[] = [title] - const titleFromTab = tab ? tab[0].toUpperCase() + tab.slice(1) : '' - - if (titleFromTab) { - titleFragments.unshift(titleFromTab) - } - - if (profile) { - titleFragments.unshift(profile.handle) - } else if (repo) { - titleFragments.unshift(repo.handle) - } else { - titleFragments.unshift(id) - } - - document.title = titleFragments.join(' - ') - }, [id, repo, profile, tab]) + const pageTitle = buildPageTitle({ + handle: profile?.handle || repo?.handle || id, + tab, + }) + useTitle(pageTitle) return ( <> diff --git a/app/repositories/page-content.tsx b/app/repositories/page-content.tsx index e5e08916..11d6bb39 100644 --- a/app/repositories/page-content.tsx +++ b/app/repositories/page-content.tsx @@ -4,6 +4,7 @@ import { useSearchParams } from 'next/navigation' import { useInfiniteQuery } from '@tanstack/react-query' import client from '@/lib/client' import { useEffect } from 'react' +import { useTitle } from 'react-use' export default function RepositoriesListPage() { const params = useSearchParams() @@ -24,16 +25,12 @@ export default function RepositoriesListPage() { getNextPageParam: (lastPage) => lastPage.cursor, }) - // Change title dynamically, if there's a search term, include that - useEffect(() => { - let title = `Repositories` + let pageTitle = `Repositories` + if (term) { + pageTitle += ` - ${term}` + } - if (term) { - title += ` - ${term}` - } - - document.title = title - }, [term]) + useTitle(pageTitle) const repos = data?.pages.flatMap((page) => page.repos) ?? [] return ( diff --git a/app/subject-status/page.tsx b/app/subject-status/page.tsx index d7397cac..86247abe 100644 --- a/app/subject-status/page.tsx +++ b/app/subject-status/page.tsx @@ -5,6 +5,7 @@ import { Loading, LoadingFailed } from '@/common/Loader' import { useSearchParams } from 'next/navigation' import { SubjectStatusView } from '@/subject/StatusView' import { useEffect } from 'react' +import { useTitle } from 'react-use' export default function SubjectStatus() { const params = useSearchParams() @@ -22,15 +23,13 @@ export default function SubjectStatus() { }, }) - useEffect(() => { - let title = `Subject Status` + let pageTitle = `Subject Status` - if (data?.subjectStatuses[0]) { - title = `${data.subjectStatuses[0].subjectRepoHandle} - ${title}` - } + if (data?.subjectStatuses[0]) { + pageTitle = `${data.subjectStatuses[0].subjectRepoHandle} - ${pageTitle}` + } - document.title = title - }, [data]) + useTitle(pageTitle) if (status === 'loading') { return diff --git a/app/surprise-me/page.tsx b/app/surprise-me/page.tsx index a6e71e7a..11892276 100644 --- a/app/surprise-me/page.tsx +++ b/app/surprise-me/page.tsx @@ -1,6 +1,6 @@ 'use client' import { useEffect, useState } from 'react' -import { useInterval } from 'react-use' +import { useInterval, useTitle } from 'react-use' import dynamic from 'next/dynamic' // The game package uses some client only code so we can't really import and use it here because that breaks SSR for some reason @@ -38,9 +38,7 @@ const Timer = () => { // Right now, we only serve the tetris game here, in the future, we want to rotate // between a few games/fun activities which is why it's named "surprise me" export default function SurpriseMePage() { - useEffect(() => { - document.title = `Take a break!` - }, []) + useTitle(`Take a break!`) return ( <>