diff --git a/apps/app/src/pages/org/[slug]/[orgLocationId]/edit.tsx b/apps/app/src/pages/org/[slug]/[orgLocationId]/edit.tsx index 71f05302b1f..670dfed04f3 100644 --- a/apps/app/src/pages/org/[slug]/[orgLocationId]/edit.tsx +++ b/apps/app/src/pages/org/[slug]/[orgLocationId]/edit.tsx @@ -57,6 +57,7 @@ const OrgLocationPage: NextPage { apiUtils.location.invalidate() apiUtils.service.invalidate() + revalidatePage({ path: router.asPath.replace('/edit', '') }) notifySave() }, }) diff --git a/apps/app/src/pages/org/[slug]/[orgLocationId]/index.tsx b/apps/app/src/pages/org/[slug]/[orgLocationId]/index.tsx index 8eeaae0e71d..5d1758f2959 100644 --- a/apps/app/src/pages/org/[slug]/[orgLocationId]/index.tsx +++ b/apps/app/src/pages/org/[slug]/[orgLocationId]/index.tsx @@ -40,14 +40,18 @@ const OrgLocationPage: NextPage = () => { const theme = useMantineTheme() const isTablet = useMediaQuery(`(max-width: ${theme.breakpoints.sm})`) - const { data: orgData, status: orgDataStatus } = api.organization.forLocationPage.useQuery( - { slug }, - { enabled: router.isReady } - ) - const { data, status } = api.location.forLocationPage.useQuery( - { id: orgLocationId }, - { enabled: router.isReady } - ) + const { + data: orgData, + status: orgDataStatus, + isError: orgDataIsError, + error: orgDataError, + } = api.organization.forLocationPage.useQuery({ slug }, { enabled: router.isReady }) + const { + data, + status, + isError: pageFetchIsError, + error: pageFetchError, + } = api.location.forLocationPage.useQuery({ id: orgLocationId }, { enabled: router.isReady }) const { data: alertData } = api.location.getAlerts.useQuery( { id: orgLocationId }, @@ -84,6 +88,13 @@ const OrgLocationPage: NextPage = () => { } }, []) + if ( + (orgDataIsError || pageFetchIsError) && + (orgDataError?.data?.code === 'NOT_FOUND' || pageFetchError?.data?.code === 'NOT_FOUND') + ) { + router.replace('/404') + } + if (loading || !data || !orgData || router.isFallback) { return } @@ -202,7 +213,7 @@ export const getStaticProps: GetStaticProps< const orgId = await ssg.organization.getIdFromSlug.fetch({ slug }) if (!orgId?.id) { - return { notFound: true } + return { notFound: true, revalidate: 1 } } const [i18n] = await Promise.allSettled([ @@ -223,7 +234,7 @@ export const getStaticProps: GetStaticProps< } catch (error) { const TRPCError = (await import('@trpc/server')).TRPCError if (error instanceof TRPCError && error.code === 'NOT_FOUND') { - return { notFound: true } + return { notFound: true, revalidate: 1 } } return { redirect: { destination: '/500', permanent: false } } } diff --git a/apps/app/src/pages/org/[slug]/edit.tsx b/apps/app/src/pages/org/[slug]/edit.tsx index 78a3fa23abf..07bdc47fadc 100644 --- a/apps/app/src/pages/org/[slug]/edit.tsx +++ b/apps/app/src/pages/org/[slug]/edit.tsx @@ -40,12 +40,14 @@ const OrganizationPage: NextPageWithOptions { if (data && newData && data.slug !== newData.slug) { router.replace({ pathname: router.pathname, query: { ...router.query, slug: newData.slug } }) } apiUtils.organization.forOrgPageEdits.invalidate() + revalidatePage({ path: router.asPath.replace('/edit', '') }) }, }) diff --git a/apps/app/src/pages/org/[slug]/index.tsx b/apps/app/src/pages/org/[slug]/index.tsx index d1cf38e7b73..84d306f866f 100644 --- a/apps/app/src/pages/org/[slug]/index.tsx +++ b/apps/app/src/pages/org/[slug]/index.tsx @@ -44,7 +44,12 @@ const OrganizationPage = ({ }: InferGetStaticPropsType) => { const router = useRouter<'/org/[slug]'>() const slug = passedSlug ?? router.query.slug - const { data, status } = api.organization.forOrgPage.useQuery({ slug }) + const { + data, + status, + isError: pageFetchIsError, + error: pageFetchError, + } = api.organization.forOrgPage.useQuery({ slug }) // const { query } = router const { t } = useTranslation(formatNS(orgId)) const [activeTab, setActiveTab] = useState('services') @@ -131,6 +136,10 @@ const OrganizationPage = ({ [isTablet, ref, width] ) + if (pageFetchIsError && pageFetchError.data?.code === 'NOT_FOUND') { + router.replace('/404') + } + if (loading || !data || router.isFallback) { return } @@ -289,7 +298,7 @@ export const getStaticProps: GetStaticProps< } catch (error) { const TRPCError = (await import('@trpc/server')).TRPCError if (error instanceof TRPCError && error.code === 'NOT_FOUND') { - return { notFound: true } + return { notFound: true, revalidate: 1 } } else { return { redirect: { destination: '/500', permanent: false } } } diff --git a/packages/api/router/misc/index.ts b/packages/api/router/misc/index.ts index 0c4e9a3a2ef..99a4c9f55d7 100644 --- a/packages/api/router/misc/index.ts +++ b/packages/api/router/misc/index.ts @@ -29,4 +29,13 @@ export const miscRouter = defineRouter({ ) return handler(opts) }), + revalidatePage: permissionedProcedure('createNewOrgQuick') + .input(schema.ZRevalidatePageSchema) + .mutation(async (opts) => { + const handler = await importHandler( + namespaced('revalidatePage'), + () => import('./mutation.revalidatePage.handler') + ) + return handler(opts) + }), }) diff --git a/packages/api/router/misc/mutation.revalidatePage.handler.ts b/packages/api/router/misc/mutation.revalidatePage.handler.ts new file mode 100644 index 00000000000..aa4553ce9b1 --- /dev/null +++ b/packages/api/router/misc/mutation.revalidatePage.handler.ts @@ -0,0 +1,24 @@ +import { type TRPCHandlerParams } from '~api/types/handler' + +import { type TRevalidatePageSchema } from './mutation.revalidatePage.schema' + +const revalidatePage = async ({ ctx, input }: TRPCHandlerParams) => { + try { + if (!ctx.res) { + return { + revalidated: false, + error: 'Response object is not available', + } + } + await ctx.res.revalidate(input.path) + return { + revalidated: true, + } + } catch (error) { + return { + revalidated: false, + error, + } + } +} +export default revalidatePage diff --git a/packages/api/router/misc/mutation.revalidatePage.schema.ts b/packages/api/router/misc/mutation.revalidatePage.schema.ts new file mode 100644 index 00000000000..b9cd683af58 --- /dev/null +++ b/packages/api/router/misc/mutation.revalidatePage.schema.ts @@ -0,0 +1,4 @@ +import { z } from 'zod' + +export const ZRevalidatePageSchema = z.object({ path: z.string() }) +export type TRevalidatePageSchema = z.infer diff --git a/packages/api/router/misc/schemas.ts b/packages/api/router/misc/schemas.ts index 7b1c6643522..e2e81042a9e 100644 --- a/packages/api/router/misc/schemas.ts +++ b/packages/api/router/misc/schemas.ts @@ -1,4 +1,5 @@ // codegen:start {preset: barrel, include: ./*.schema.ts} +export * from './mutation.revalidatePage.schema' export * from './query.forEditNavbar.schema' export * from './query.getCountryTranslation.schema' export * from './query.hasContactInfo.schema' diff --git a/packages/ui/components/sections/Navbar.tsx b/packages/ui/components/sections/Navbar.tsx index 41711660c38..6d807f4ee6c 100644 --- a/packages/ui/components/sections/Navbar.tsx +++ b/packages/ui/components/sections/Navbar.tsx @@ -65,7 +65,7 @@ const EditModeBar = () => { const { t } = useTranslation('common') const router = useRouter<'/org/[slug]/edit' | '/org/[slug]/[orgLocationId]/edit'>() const { orgLocationId, slug, orgServiceId } = router.query - + const { mutate: revalidatePage } = api.misc.revalidatePage.useMutation() const apiQuery = (() => { switch (true) { case typeof orgServiceId === 'string': { @@ -91,6 +91,7 @@ const EditModeBar = () => { onSuccess: () => { apiUtils.organization.invalidate() apiUtils.component.EditModeBar.invalidate() + revalidatePage({ path: router.asPath.replace('/edit', '') }) reverifyNotification() }, }) @@ -103,6 +104,7 @@ const EditModeBar = () => { apiUtils.location.invalidate() apiUtils.organization.invalidate() apiUtils.component.EditModeBar.invalidate() + revalidatePage({ path: router.asPath.replace('/edit', '') }) publishedNotification() }, }) @@ -114,6 +116,7 @@ const EditModeBar = () => { onSuccess: () => { apiUtils.organization.invalidate() apiUtils.component.EditModeBar.invalidate() + revalidatePage({ path: router.asPath.replace('/edit', '') }) deletedNotification() }, })