diff --git a/.eslintrc b/.eslintrc index 2fcb4d5a3..94b3e0c0a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -133,8 +133,8 @@ // Custom local rules "local-rules/require-react-import-when-using-namespace": "error", "local-rules/require-satisfies-on-nested-prisma-selects": "error", - "local-rules/require-deleted-at-check-on-custom-field-queries": "error" - // "local-rules/require-meta-export-in-routes": "warn" + "local-rules/require-deleted-at-check-on-custom-field-queries": "error", + "local-rules/require-meta-export-in-routes": "warn" }, "overrides": [ { diff --git a/app/routes/_auth+/_auth.tsx b/app/routes/_auth+/_auth.tsx index de6235bc5..ad186fb21 100644 --- a/app/routes/_auth+/_auth.tsx +++ b/app/routes/_auth+/_auth.tsx @@ -2,9 +2,12 @@ import { Link, useMatches, Outlet } from "react-router"; import { ErrorContent } from "~/components/errors"; import { ShelfSymbolLogo } from "~/components/marketing/logos"; import SubHeading from "~/components/shared/sub-heading"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; export const loader = () => null; +export const meta = () => [{ title: appendToMetaTitle("Authentication") }]; + export default function App() { const matches = useMatches(); /** Find the title and subHeading from current route */ diff --git a/app/routes/_auth+/accept-invite.$inviteId.tsx b/app/routes/_auth+/accept-invite.$inviteId.tsx index 882dd0d44..bde784184 100644 --- a/app/routes/_auth+/accept-invite.$inviteId.tsx +++ b/app/routes/_auth+/accept-invite.$inviteId.tsx @@ -19,6 +19,7 @@ import { updateInviteStatus, } from "~/modules/invite/service.server"; import { setSelectedOrganizationIdCookie } from "~/modules/organization/context.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { setCookie } from "~/utils/cookies.server"; import { INVITE_TOKEN_SECRET, SUPPORT_EMAIL } from "~/utils/env"; import { ShelfError, makeShelfError } from "~/utils/error"; @@ -91,6 +92,8 @@ export async function loader({ context, params }: LoaderFunctionArgs) { } } +export const meta = () => [{ title: appendToMetaTitle("Accept team invite") }]; + export async function action({ context, request }: LoaderFunctionArgs) { try { const { token } = parseData( diff --git a/app/routes/_auth+/oauth.callback.tsx b/app/routes/_auth+/oauth.callback.tsx index ea515a88a..0974323fd 100644 --- a/app/routes/_auth+/oauth.callback.tsx +++ b/app/routes/_auth+/oauth.callback.tsx @@ -1,6 +1,10 @@ import { useEffect, useMemo } from "react"; -import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router"; +import type { + ActionFunctionArgs, + LoaderFunctionArgs, + MetaFunction, +} from "react-router"; import { data, redirect, useFetcher } from "react-router"; import { z } from "zod"; import { Button } from "~/components/shared/button"; @@ -10,6 +14,7 @@ import { useSearchParams } from "~/hooks/search-params"; import { supabaseClient } from "~/integrations/supabase/client"; import { refreshAccessToken } from "~/modules/auth/service.server"; import { setSelectedOrganizationIdCookie } from "~/modules/organization/context.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { createSSOFormData } from "~/utils/auth"; import { setCookie } from "~/utils/cookies.server"; import { makeShelfError, notAllowedMethod, ShelfError } from "~/utils/error"; @@ -154,6 +159,11 @@ export function loader({ context }: LoaderFunctionArgs) { return data(payload({ title, subHeading })); } + +export const meta: MetaFunction = ({ data }) => [ + { title: data ? appendToMetaTitle(data.title) : "" }, +]; + export default function LoginCallback() { const fetcher = useFetcher(); const { data } = fetcher; diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index b38e8ceec..5ba5ffd5b 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -1,5 +1,8 @@ import type { LoaderFunctionArgs } from "react-router"; import { redirect } from "react-router"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; + +export const meta = () => [{ title: appendToMetaTitle("Home") }]; export const loader = ({ context }: LoaderFunctionArgs) => { if (context.isAuthenticated) { diff --git a/app/routes/_layout+/account-details.workspace.new.tsx b/app/routes/_layout+/account-details.workspace.new.tsx index 2cb1f0b5b..01fc53d43 100644 --- a/app/routes/_layout+/account-details.workspace.new.tsx +++ b/app/routes/_layout+/account-details.workspace.new.tsx @@ -5,7 +5,11 @@ import { } from "@remix-run/form-data-parser"; import { invariant } from "framer-motion"; import { useAtomValue } from "jotai"; -import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router"; +import type { + ActionFunctionArgs, + LoaderFunctionArgs, + MetaFunction, +} from "react-router"; import { data, redirect } from "react-router"; import { dynamicTitleAtom } from "~/atoms/dynamic-title-atom"; import Header from "~/components/layout/header"; @@ -21,6 +25,7 @@ import { setSelectedOrganizationIdCookie, } from "~/modules/organization/context.server"; import { createOrganization } from "~/modules/organization/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { DEFAULT_MAX_IMAGE_UPLOAD_SIZE } from "~/utils/constants"; import { setCookie } from "~/utils/cookies.server"; import { sendNotification } from "~/utils/emitter/send-notification.server"; @@ -55,6 +60,10 @@ export async function loader({ context, request }: LoaderFunctionArgs) { } } +export const meta: MetaFunction = ({ data }) => [ + { title: data ? appendToMetaTitle(data.header.title) : "" }, +]; + export async function action({ context, request }: ActionFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/account-details.workspace.tsx b/app/routes/_layout+/account-details.workspace.tsx index 8aa8ad882..9d97deacc 100644 --- a/app/routes/_layout+/account-details.workspace.tsx +++ b/app/routes/_layout+/account-details.workspace.tsx @@ -1,5 +1,8 @@ import { Link, Outlet } from "react-router"; import { ErrorContent } from "~/components/errors"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; + +export const meta = () => [{ title: appendToMetaTitle("Workspaces") }]; export const handle = { breadcrumb: () => Workspaces, diff --git a/app/routes/_layout+/admin-dashboard+/$userId.tsx b/app/routes/_layout+/admin-dashboard+/$userId.tsx index dc63e31ab..67f074476 100644 --- a/app/routes/_layout+/admin-dashboard+/$userId.tsx +++ b/app/routes/_layout+/admin-dashboard+/$userId.tsx @@ -29,6 +29,7 @@ import { useDisabled } from "~/hooks/use-disabled"; import { resetPersonalWorkspaceBranding } from "~/modules/organization/service.server"; import { updateUserTierId } from "~/modules/tier/service.server"; import { softDeleteUser, getUserByID } from "~/modules/user/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError, ShelfError } from "~/utils/error"; import { @@ -47,6 +48,8 @@ import { getStripePricesAndProducts, } from "~/utils/stripe.server"; +export const meta = () => [{ title: appendToMetaTitle("User details") }]; + export type QrCodeWithAsset = Qr & { asset: { title: Asset["title"]; diff --git a/app/routes/_layout+/admin-dashboard+/_layout.tsx b/app/routes/_layout+/admin-dashboard+/_layout.tsx index ce6f7f465..3cc3054d3 100644 --- a/app/routes/_layout+/admin-dashboard+/_layout.tsx +++ b/app/routes/_layout+/admin-dashboard+/_layout.tsx @@ -3,6 +3,7 @@ import { data, Link, Outlet } from "react-router"; import { ErrorContent } from "~/components/errors"; import HorizontalTabs from "~/components/layout/horizontal-tabs"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error } from "~/utils/http.server"; import { requireAdmin } from "~/utils/roles.server"; @@ -21,6 +22,8 @@ export async function loader({ context }: LoaderFunctionArgs) { } } +export const meta = () => [{ title: appendToMetaTitle("Admin dashboard") }]; + export const handle = { breadcrumb: () => Admin dashboard, }; diff --git a/app/routes/_layout+/admin-dashboard+/announcements.new.tsx b/app/routes/_layout+/admin-dashboard+/announcements.new.tsx index c12f4a3b4..c071a59b4 100644 --- a/app/routes/_layout+/admin-dashboard+/announcements.new.tsx +++ b/app/routes/_layout+/admin-dashboard+/announcements.new.tsx @@ -7,10 +7,13 @@ import { Switch } from "~/components/forms/switch"; import { MarkdownEditor } from "~/components/markdown/markdown-editor"; import { Button } from "~/components/shared/button"; import { db } from "~/database/db.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError, ShelfError } from "~/utils/error"; import { payload, error, parseData } from "~/utils/http.server"; import { requireAdmin } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("New announcement") }]; + export const loader = async ({ context }: LoaderFunctionArgs) => { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/admin-dashboard+/announcements.tsx b/app/routes/_layout+/admin-dashboard+/announcements.tsx index b7058a5e2..77e356a80 100644 --- a/app/routes/_layout+/admin-dashboard+/announcements.tsx +++ b/app/routes/_layout+/admin-dashboard+/announcements.tsx @@ -6,11 +6,14 @@ import { MarkdownViewer } from "~/components/markdown/markdown-viewer"; import { Button } from "~/components/shared/button"; import { Table, Td, Th, Tr } from "~/components/table"; import { db } from "~/database/db.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError, ShelfError } from "~/utils/error"; import { payload, error, parseData } from "~/utils/http.server"; import { parseMarkdownToReact } from "~/utils/md"; import { requireAdmin } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Announcements") }]; + export const loader = async ({ context }: LoaderFunctionArgs) => { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/admin-dashboard+/generate-locations.tsx b/app/routes/_layout+/admin-dashboard+/generate-locations.tsx index 7a3dc77fc..b009ef296 100644 --- a/app/routes/_layout+/admin-dashboard+/generate-locations.tsx +++ b/app/routes/_layout+/admin-dashboard+/generate-locations.tsx @@ -10,6 +10,7 @@ import Input from "~/components/forms/input"; import { Button } from "~/components/shared/button"; import { useDisabled } from "~/hooks/use-disabled"; import { generateLocationWithImages } from "~/modules/location/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { DEFAULT_MAX_IMAGE_UPLOAD_SIZE } from "~/utils/constants"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError, ShelfError } from "~/utils/error"; @@ -24,6 +25,7 @@ const GenerateLocationSchema = z.object({ numberOfLocations: z.coerce.number().min(1).max(500).default(100), image: z.instanceof(File, { message: "Image is required" }), }); +export const meta = () => [{ title: appendToMetaTitle("Generate locations") }]; export async function loader({ context }: LoaderFunctionArgs) { const { userId } = context.getSession(); diff --git a/app/routes/_layout+/admin-dashboard+/move-location-images.tsx b/app/routes/_layout+/admin-dashboard+/move-location-images.tsx index 4ce02455f..4616e322b 100644 --- a/app/routes/_layout+/admin-dashboard+/move-location-images.tsx +++ b/app/routes/_layout+/admin-dashboard+/move-location-images.tsx @@ -9,6 +9,7 @@ import { Button } from "~/components/shared/button"; import { db } from "~/database/db.server"; import { useDisabled } from "~/hooks/use-disabled"; import { getSupabaseAdmin } from "~/integrations/supabase/client"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { PUBLIC_BUCKET } from "~/utils/constants"; import { cropImage } from "~/utils/crop-image"; import { sendNotification } from "~/utils/emitter/send-notification.server"; @@ -25,6 +26,9 @@ export const MigrationFormSchema = z.object({ .transform((value) => value === "on"), }); +export const meta = () => [ + { title: appendToMetaTitle("Move location images") }, +]; export async function loader({ context }: LoaderFunctionArgs) { const { userId } = context.getSession(); diff --git a/app/routes/_layout+/admin-dashboard+/org.$organizationId.assets.tsx b/app/routes/_layout+/admin-dashboard+/org.$organizationId.assets.tsx index a384d9be8..da1582492 100644 --- a/app/routes/_layout+/admin-dashboard+/org.$organizationId.assets.tsx +++ b/app/routes/_layout+/admin-dashboard+/org.$organizationId.assets.tsx @@ -9,6 +9,7 @@ import { } from "~/modules/asset/service.server"; import { CurrentSearchParamsSchema } from "~/modules/asset/utils.server"; import { getAssetIndexSettings } from "~/modules/asset-index-settings/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { checkExhaustiveSwitch } from "~/utils/check-exhaustive-switch"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError } from "~/utils/error"; @@ -19,6 +20,8 @@ import { } from "~/utils/permissions/permission.data"; import { requireAdmin, requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Organization assets") }]; + export const loader = async ({ request, context, diff --git a/app/routes/_layout+/admin-dashboard+/org.$organizationId.members.tsx b/app/routes/_layout+/admin-dashboard+/org.$organizationId.members.tsx index f065e3353..ae1680ce8 100644 --- a/app/routes/_layout+/admin-dashboard+/org.$organizationId.members.tsx +++ b/app/routes/_layout+/admin-dashboard+/org.$organizationId.members.tsx @@ -5,10 +5,15 @@ import { DateS } from "~/components/shared/date"; import { Table, Td, Tr } from "~/components/table"; import { SSOUserBadge } from "~/components/user/sso-user-badge"; import { db } from "~/database/db.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error, getParams } from "~/utils/http.server"; import { requireAdmin } from "~/utils/roles.server"; +export const meta = () => [ + { title: appendToMetaTitle("Organization members") }, +]; + export const loader = async ({ context, params }: LoaderFunctionArgs) => { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/admin-dashboard+/org.$organizationId.qr-codes.tsx b/app/routes/_layout+/admin-dashboard+/org.$organizationId.qr-codes.tsx index 0cddfa2e5..f8bc673cb 100644 --- a/app/routes/_layout+/admin-dashboard+/org.$organizationId.qr-codes.tsx +++ b/app/routes/_layout+/admin-dashboard+/org.$organizationId.qr-codes.tsx @@ -7,10 +7,15 @@ import { DateS } from "~/components/shared/date"; import { Table, Td, Tr } from "~/components/table"; import { db } from "~/database/db.server"; import { generateOrphanedCodes } from "~/modules/qr/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError, ShelfError } from "~/utils/error"; import { payload, error, getParams, parseData } from "~/utils/http.server"; import { requireAdmin } from "~/utils/roles.server"; +export const meta = () => [ + { title: appendToMetaTitle("Organization QR codes") }, +]; + export const loader = async ({ context, params }: LoaderFunctionArgs) => { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/admin-dashboard+/org.$organizationId.transfer-ownership.tsx b/app/routes/_layout+/admin-dashboard+/org.$organizationId.transfer-ownership.tsx index 2f547e8d3..9f6806acb 100644 --- a/app/routes/_layout+/admin-dashboard+/org.$organizationId.transfer-ownership.tsx +++ b/app/routes/_layout+/admin-dashboard+/org.$organizationId.transfer-ownership.tsx @@ -2,10 +2,15 @@ import { data, type LoaderFunctionArgs } from "react-router"; import z from "zod"; import TransferOwnershipCard from "~/components/settings/transfer-ownership-card"; import { getOrganizationAdmins } from "~/modules/organization/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { error, getParams, payload } from "~/utils/http.server"; import { requireAdmin } from "~/utils/roles.server"; +export const meta = () => [ + { title: appendToMetaTitle("Transfer organization ownership") }, +]; + export async function loader({ context, params }: LoaderFunctionArgs) { const { userId } = context.getSession(); const { organizationId } = getParams( diff --git a/app/routes/_layout+/admin-dashboard+/org.$organizationId.tsx b/app/routes/_layout+/admin-dashboard+/org.$organizationId.tsx index cdf73e964..5725f9d3b 100644 --- a/app/routes/_layout+/admin-dashboard+/org.$organizationId.tsx +++ b/app/routes/_layout+/admin-dashboard+/org.$organizationId.tsx @@ -28,6 +28,8 @@ import { toggleBarcodeEnabled, } from "~/modules/organization/service.server"; import { createDefaultWorkingHours } from "~/modules/working-hours/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; + import { csvDataFromRequest } from "~/utils/csv.server"; import { ShelfError, makeShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; @@ -36,6 +38,9 @@ import { extractCSVDataFromContentImport } from "~/utils/import.server"; import { requireAdmin } from "~/utils/roles.server"; import { validateDomains } from "~/utils/sso.server"; +export const meta = () => [ + { title: appendToMetaTitle("Organization details") }, +]; export const loader = async ({ context, params }: LoaderFunctionArgs) => { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/admin-dashboard+/qrs.tsx b/app/routes/_layout+/admin-dashboard+/qrs.tsx index d9135862e..fce1b4881 100644 --- a/app/routes/_layout+/admin-dashboard+/qrs.tsx +++ b/app/routes/_layout+/admin-dashboard+/qrs.tsx @@ -1,5 +1,9 @@ import type { PrintBatch, Prisma } from "@prisma/client"; -import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router"; +import type { + ActionFunctionArgs, + LoaderFunctionArgs, + MetaFunction, +} from "react-router"; import { data, redirect, @@ -28,6 +32,7 @@ import { getPaginatedAndFilterableQrCodes, markBatchAsPrinted, } from "~/modules/qr/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; import { payload, error, parseData } from "~/utils/http.server"; @@ -78,6 +83,10 @@ export async function loader({ context, request }: LoaderFunctionArgs) { } } +export const meta: MetaFunction = ({ loaderData }) => [ + { title: appendToMetaTitle(loaderData?.header.title) }, +]; + export async function action({ context, request }: ActionFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/admin-dashboard+/test-supabase-rls.tsx b/app/routes/_layout+/admin-dashboard+/test-supabase-rls.tsx index 5d3e58b43..db7a2f514 100644 --- a/app/routes/_layout+/admin-dashboard+/test-supabase-rls.tsx +++ b/app/routes/_layout+/admin-dashboard+/test-supabase-rls.tsx @@ -3,10 +3,13 @@ import { useEffect, useState } from "react"; import { data, type LoaderFunctionArgs } from "react-router"; import { Button } from "~/components/shared/button"; import { supabaseClient } from "~/integrations/supabase/client"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error } from "~/utils/http.server"; import { requireAdmin } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Test Supabase RLS") }]; + export const loader = async ({ context }: LoaderFunctionArgs) => { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/admin-dashboard+/updates.$updateId.edit.tsx b/app/routes/_layout+/admin-dashboard+/updates.$updateId.edit.tsx index afae17f8b..e6b1bea6a 100644 --- a/app/routes/_layout+/admin-dashboard+/updates.$updateId.edit.tsx +++ b/app/routes/_layout+/admin-dashboard+/updates.$updateId.edit.tsx @@ -5,10 +5,13 @@ import { z } from "zod"; import { Card } from "~/components/shared/card"; import { UpdateForm } from "~/components/update/update-form"; import { getUpdateById, updateUpdate } from "~/modules/update/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error, parseData } from "~/utils/http.server"; import { requireAdmin } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Edit update") }]; + export const loader = async ({ context, params }: LoaderFunctionArgs) => { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/admin-dashboard+/updates.new.tsx b/app/routes/_layout+/admin-dashboard+/updates.new.tsx index ce1ed26bd..3a527cd1d 100644 --- a/app/routes/_layout+/admin-dashboard+/updates.new.tsx +++ b/app/routes/_layout+/admin-dashboard+/updates.new.tsx @@ -5,10 +5,13 @@ import { z } from "zod"; import { Card } from "~/components/shared/card"; import { UpdateForm } from "~/components/update/update-form"; import { createUpdate } from "~/modules/update/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error, parseData } from "~/utils/http.server"; import { requireAdmin } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("New update") }]; + export const loader = async ({ context }: LoaderFunctionArgs) => { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/admin-dashboard+/updates.tsx b/app/routes/_layout+/admin-dashboard+/updates.tsx index dc91d9e24..ce4d0679e 100644 --- a/app/routes/_layout+/admin-dashboard+/updates.tsx +++ b/app/routes/_layout+/admin-dashboard+/updates.tsx @@ -11,10 +11,13 @@ import { getAllUpdatesForAdmin, updateUpdate, } from "~/modules/update/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error, parseData } from "~/utils/http.server"; import { requireAdmin } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Updates") }]; + export const loader = async ({ context }: LoaderFunctionArgs) => { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/admin-dashboard+/users.tsx b/app/routes/_layout+/admin-dashboard+/users.tsx index 4c351ef25..295e03bd7 100644 --- a/app/routes/_layout+/admin-dashboard+/users.tsx +++ b/app/routes/_layout+/admin-dashboard+/users.tsx @@ -1,6 +1,6 @@ import type { User } from "@prisma/client"; import { TierId } from "@prisma/client"; -import type { LoaderFunctionArgs } from "react-router"; +import type { LoaderFunctionArgs, MetaFunction } from "react-router"; import { data, useNavigate, useLoaderData } from "react-router"; import { StatusFilter } from "~/components/booking/status-filter"; import { ErrorContent } from "~/components/errors"; @@ -11,6 +11,7 @@ import { Pagination } from "~/components/list/pagination"; import { DateS } from "~/components/shared/date"; import { Td, Th } from "~/components/table"; import { getPaginatedAndFilterableUsers } from "~/modules/user/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error } from "~/utils/http.server"; import { requireAdmin } from "~/utils/roles.server"; @@ -61,6 +62,10 @@ export async function loader({ context, request }: LoaderFunctionArgs) { } } +export const meta: MetaFunction = ({ loaderData }) => [ + { title: loaderData ? appendToMetaTitle(loaderData.header.title) : "" }, +]; + export default function Area51() { const navigate = useNavigate(); const { tierItems } = useLoaderData(); diff --git a/app/routes/_layout+/assets.$assetId.bookings.tsx b/app/routes/_layout+/assets.$assetId.bookings.tsx index 128e2b6c7..ec86cc890 100644 --- a/app/routes/_layout+/assets.$assetId.bookings.tsx +++ b/app/routes/_layout+/assets.$assetId.bookings.tsx @@ -1,5 +1,5 @@ import { BookingStatus } from "@prisma/client"; -import { data, type LoaderFunctionArgs } from "react-router"; +import { data, type LoaderFunctionArgs, type MetaFunction } from "react-router"; import { z } from "zod"; import type { HeaderData } from "~/components/layout/header/types"; import { hasGetAllValue } from "~/hooks/use-model-filters"; @@ -10,6 +10,7 @@ import { import { setSelectedOrganizationIdCookie } from "~/modules/organization/context.server"; import { getTagsForBookingTagsFilter } from "~/modules/tag/service.server"; import { getTeamMemberForCustodianFilter } from "~/modules/team-member/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { setCookie, updateCookieWithPerPage, @@ -41,6 +42,10 @@ const BOOKING_STATUS_TO_SHOW = [ BookingStatus.RESERVED, ]; +export const meta: MetaFunction = ({ data }) => [ + { title: data ? appendToMetaTitle(data.header.title) : "" }, +]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/assets.$assetId.note.tsx b/app/routes/_layout+/assets.$assetId.note.tsx index fb8a09825..44106e664 100644 --- a/app/routes/_layout+/assets.$assetId.note.tsx +++ b/app/routes/_layout+/assets.$assetId.note.tsx @@ -4,6 +4,7 @@ import { z } from "zod"; import { MarkdownNoteSchema } from "~/components/notes/markdown-note-form"; import { db } from "~/database/db.server"; import { createNote, deleteNote } from "~/modules/note/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError, notAllowedMethod, ShelfError } from "~/utils/error"; import { @@ -19,6 +20,8 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Asset notes") }]; + export function loader({ params }: LoaderFunctionArgs) { const { assetId } = getParams(params, z.object({ assetId: z.string() })); diff --git a/app/routes/_layout+/assets.$assetId.overview.add-to-existing-booking.tsx b/app/routes/_layout+/assets.$assetId.overview.add-to-existing-booking.tsx index c7ea4d270..5d36dc756 100644 --- a/app/routes/_layout+/assets.$assetId.overview.add-to-existing-booking.tsx +++ b/app/routes/_layout+/assets.$assetId.overview.add-to-existing-booking.tsx @@ -23,6 +23,7 @@ import { createNotes } from "~/modules/note/service.server"; import { setSelectedOrganizationIdCookie } from "~/modules/organization/context.server"; import { getUserByID } from "~/modules/user/service.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { setCookie } from "~/utils/cookies.server"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError, ShelfError } from "~/utils/error"; @@ -42,6 +43,8 @@ const updateBookingSchema = z.object({ bookingId: z.string().min(1, "Please select a booking."), }); +export const meta = () => [{ title: appendToMetaTitle("Add to booking") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/assets.$assetId.overview.assign-custody.tsx b/app/routes/_layout+/assets.$assetId.overview.assign-custody.tsx index 230cc13b7..ed4962a36 100644 --- a/app/routes/_layout+/assets.$assetId.overview.assign-custody.tsx +++ b/app/routes/_layout+/assets.$assetId.overview.assign-custody.tsx @@ -24,6 +24,7 @@ import { createNote } from "~/modules/note/service.server"; import { getTeamMember } from "~/modules/team-member/service.server"; import { getUserByID } from "~/modules/user/service.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { ShelfError, makeShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; @@ -45,6 +46,8 @@ import { import { requirePermission } from "~/utils/roles.server"; import { resolveTeamMemberName } from "~/utils/user"; +export const meta = () => [{ title: appendToMetaTitle("Assign custody") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/assets.$assetId.overview.create-new-booking.tsx b/app/routes/_layout+/assets.$assetId.overview.create-new-booking.tsx index 8d5db0a6f..72cd06523 100644 --- a/app/routes/_layout+/assets.$assetId.overview.create-new-booking.tsx +++ b/app/routes/_layout+/assets.$assetId.overview.create-new-booking.tsx @@ -8,6 +8,7 @@ import { getTeamMemberForForm } from "~/modules/team-member/service.server"; import NewBooking, { action as newBookingAction, } from "~/routes/_layout+/bookings.new"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError, ShelfError } from "~/utils/error"; import { payload, @@ -22,6 +23,8 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Create new booking") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const searchParams = getCurrentSearchParams(request); const authSession = context.getSession(); diff --git a/app/routes/_layout+/assets.$assetId.overview.duplicate.tsx b/app/routes/_layout+/assets.$assetId.overview.duplicate.tsx index 42ca773ac..6a1559f6d 100644 --- a/app/routes/_layout+/assets.$assetId.overview.duplicate.tsx +++ b/app/routes/_layout+/assets.$assetId.overview.duplicate.tsx @@ -18,6 +18,7 @@ import { Button } from "~/components/shared/button"; import { Spinner } from "~/components/shared/spinner"; import { duplicateAsset, getAsset } from "~/modules/asset/service.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { MAX_DUPLICATES_ALLOWED } from "~/utils/constants"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError } from "~/utils/error"; @@ -30,6 +31,8 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Duplicate asset") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/assets.$assetId.overview.release-custody.tsx b/app/routes/_layout+/assets.$assetId.overview.release-custody.tsx index c8c20a2b5..ff68eea71 100644 --- a/app/routes/_layout+/assets.$assetId.overview.release-custody.tsx +++ b/app/routes/_layout+/assets.$assetId.overview.release-custody.tsx @@ -11,6 +11,7 @@ import { releaseCustody } from "~/modules/custody/service.server"; import { createNote } from "~/modules/note/service.server"; import { getUserByID } from "~/modules/user/service.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { ShelfError, makeShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; @@ -26,6 +27,8 @@ import { import { requirePermission } from "~/utils/roles.server"; import { resolveTeamMemberName } from "~/utils/user"; +export const meta = () => [{ title: appendToMetaTitle("Release custody") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/assets.$assetId.overview.update-location.tsx b/app/routes/_layout+/assets.$assetId.overview.update-location.tsx index 88b59690b..1ae41ca35 100644 --- a/app/routes/_layout+/assets.$assetId.overview.update-location.tsx +++ b/app/routes/_layout+/assets.$assetId.overview.update-location.tsx @@ -11,6 +11,7 @@ import { updateAsset, } from "~/modules/asset/service.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; @@ -27,6 +28,8 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Update location") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/assets.$assetId.reminders.tsx b/app/routes/_layout+/assets.$assetId.reminders.tsx index d6fc899c4..568662c5e 100644 --- a/app/routes/_layout+/assets.$assetId.reminders.tsx +++ b/app/routes/_layout+/assets.$assetId.reminders.tsx @@ -1,10 +1,11 @@ -import { data } from "react-router"; +import { data, type MetaFunction } from "react-router"; import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router"; import { z } from "zod"; import RemindersTable from "~/components/asset-reminder/reminders-table"; import type { HeaderData } from "~/components/layout/header/types"; import { getPaginatedAndFilterableReminders } from "~/modules/asset-reminder/service.server"; import { resolveRemindersActions } from "~/modules/asset-reminder/utils.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error, getParams } from "~/utils/http.server"; import { @@ -13,6 +14,10 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta: MetaFunction = ({ data }) => [ + { title: data ? appendToMetaTitle(data.header.title) : "" }, +]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const userId = authSession.userId; diff --git a/app/routes/_layout+/assets.tsx b/app/routes/_layout+/assets.tsx index 5750e73c7..51a05a92d 100644 --- a/app/routes/_layout+/assets.tsx +++ b/app/routes/_layout+/assets.tsx @@ -1,6 +1,9 @@ import type { ShouldRevalidateFunctionArgs } from "react-router"; import { Link, Outlet } from "react-router"; import { ErrorContent } from "~/components/errors"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; + +export const meta = () => [{ title: appendToMetaTitle("Assets") }]; export function loader() { return null; diff --git a/app/routes/_layout+/bookings.$bookingId.overview.duplicate.tsx b/app/routes/_layout+/bookings.$bookingId.overview.duplicate.tsx index 5bc40db8e..45e4005d6 100644 --- a/app/routes/_layout+/bookings.$bookingId.overview.duplicate.tsx +++ b/app/routes/_layout+/bookings.$bookingId.overview.duplicate.tsx @@ -10,6 +10,7 @@ import { z } from "zod"; import { Button } from "~/components/shared/button"; import { useDisabled } from "~/hooks/use-disabled"; import { duplicateBooking, getBooking } from "~/modules/booking/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError } from "~/utils/error"; import { payload, error, getParams } from "~/utils/http.server"; @@ -21,6 +22,8 @@ import { requirePermission } from "~/utils/roles.server"; const paramsSchema = z.object({ bookingId: z.string() }); +export const meta = () => [{ title: appendToMetaTitle("Duplicate booking") }]; + export async function loader({ request, context, params }: LoaderFunctionArgs) { const { userId } = context.getSession(); diff --git a/app/routes/_layout+/bookings.$bookingId.overview.manage-assets.tsx b/app/routes/_layout+/bookings.$bookingId.overview.manage-assets.tsx index 258fab9f9..22c3211d1 100644 --- a/app/routes/_layout+/bookings.$bookingId.overview.manage-assets.tsx +++ b/app/routes/_layout+/bookings.$bookingId.overview.manage-assets.tsx @@ -67,6 +67,7 @@ import { } from "~/modules/booking/service.server"; import { createNotes } from "~/modules/note/service.server"; import { getUserByID } from "~/modules/user/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { isAssetPartiallyCheckedIn } from "~/utils/booking-assets"; import { makeShelfError, ShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; @@ -93,6 +94,8 @@ export type AssetWithBooking = Asset & { qrScanned: string; }; +export const meta = () => [{ title: appendToMetaTitle("Manage assets") }]; + export const links: LinksFunction = () => [{ rel: "stylesheet", href: styles }]; export async function loader({ context, request, params }: LoaderFunctionArgs) { diff --git a/app/routes/_layout+/bookings.$bookingId.overview.manage-kits.tsx b/app/routes/_layout+/bookings.$bookingId.overview.manage-kits.tsx index 21585c6a9..7b539b590 100644 --- a/app/routes/_layout+/bookings.$bookingId.overview.manage-kits.tsx +++ b/app/routes/_layout+/bookings.$bookingId.overview.manage-kits.tsx @@ -64,6 +64,7 @@ import { } from "~/modules/booking/service.server"; import { getPaginatedAndFilterableKits } from "~/modules/kit/service.server"; import { getUserByID } from "~/modules/user/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { isKitPartiallyCheckedIn } from "~/utils/booking-assets"; import { makeShelfError, ShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; @@ -74,6 +75,8 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Manage kits") }]; + export const links: LinksFunction = () => [{ rel: "stylesheet", href: styles }]; export type KitForBooking = Prisma.KitGetPayload<{ diff --git a/app/routes/_layout+/bookings.tsx b/app/routes/_layout+/bookings.tsx index 6cc5391b4..ffec49949 100644 --- a/app/routes/_layout+/bookings.tsx +++ b/app/routes/_layout+/bookings.tsx @@ -1,6 +1,9 @@ import type { ShouldRevalidateFunctionArgs } from "react-router"; import { Link, Outlet } from "react-router"; import { ErrorContent } from "~/components/errors"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; + +export const meta = () => [{ title: appendToMetaTitle("Bookings") }]; export function loader() { return null; diff --git a/app/routes/_layout+/kits.$kitId.assets.add-to-existing-booking.tsx b/app/routes/_layout+/kits.$kitId.assets.add-to-existing-booking.tsx index 16cc79a3d..d554450bd 100644 --- a/app/routes/_layout+/kits.$kitId.assets.add-to-existing-booking.tsx +++ b/app/routes/_layout+/kits.$kitId.assets.add-to-existing-booking.tsx @@ -24,6 +24,7 @@ import { createNotes } from "~/modules/note/service.server"; import { setSelectedOrganizationIdCookie } from "~/modules/organization/context.server"; import { getUserByID } from "~/modules/user/service.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { setCookie } from "~/utils/cookies.server"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError, ShelfError } from "~/utils/error"; @@ -38,6 +39,8 @@ import { import { requirePermission } from "~/utils/roles.server"; import { intersected } from "~/utils/utils"; +export const meta = () => [{ title: appendToMetaTitle("Add kit to booking") }]; + const updateBookingSchema = z.object({ bookingId: z.string().transform((val, ctx) => { if (!val && val === "") { diff --git a/app/routes/_layout+/kits.$kitId.assets.assign-custody.tsx b/app/routes/_layout+/kits.$kitId.assets.assign-custody.tsx index 5cd8f9f52..c61dc1ee0 100644 --- a/app/routes/_layout+/kits.$kitId.assets.assign-custody.tsx +++ b/app/routes/_layout+/kits.$kitId.assets.assign-custody.tsx @@ -30,6 +30,7 @@ import { createNotes } from "~/modules/note/service.server"; import { getTeamMember } from "~/modules/team-member/service.server"; import { getUserByID } from "~/modules/user/service.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError, ShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; @@ -53,6 +54,8 @@ import { import { requirePermission } from "~/utils/roles.server"; import { resolveTeamMemberName } from "~/utils/user"; +export const meta = () => [{ title: appendToMetaTitle("Assign kit custody") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/kits.$kitId.assets.create-new-booking.tsx b/app/routes/_layout+/kits.$kitId.assets.create-new-booking.tsx index 6560fbea2..1205c2aac 100644 --- a/app/routes/_layout+/kits.$kitId.assets.create-new-booking.tsx +++ b/app/routes/_layout+/kits.$kitId.assets.create-new-booking.tsx @@ -9,6 +9,7 @@ import { getTeamMemberForForm } from "~/modules/team-member/service.server"; import NewBooking, { action as newBookingAction, } from "~/routes/_layout+/bookings.new"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError, ShelfError } from "~/utils/error"; import { payload, @@ -23,6 +24,8 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Create kit booking") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const searchParams = getCurrentSearchParams(request); const authSession = context.getSession(); diff --git a/app/routes/_layout+/kits.$kitId.assets.manage-assets.tsx b/app/routes/_layout+/kits.$kitId.assets.manage-assets.tsx index 424e9134e..fe568f729 100644 --- a/app/routes/_layout+/kits.$kitId.assets.manage-assets.tsx +++ b/app/routes/_layout+/kits.$kitId.assets.manage-assets.tsx @@ -55,6 +55,7 @@ import { db } from "~/database/db.server"; import { getPaginatedAndFilterableAssets } from "~/modules/asset/service.server"; import type { AssetsFromViewItem } from "~/modules/asset/types"; import { updateKitAssets } from "~/modules/kit/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError, ShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; import { payload, error, getParams, parseData } from "~/utils/http.server"; @@ -66,6 +67,8 @@ import { import { requirePermission } from "~/utils/roles.server"; import { tw } from "~/utils/tw"; +export const meta = () => [{ title: appendToMetaTitle("Manage kit assets") }]; + type LoaderData = typeof loader; const ASSET_KIT_FILTERS = [ diff --git a/app/routes/_layout+/kits.$kitId.assets.release-custody.tsx b/app/routes/_layout+/kits.$kitId.assets.release-custody.tsx index 12caa6a10..e02c1eb54 100644 --- a/app/routes/_layout+/kits.$kitId.assets.release-custody.tsx +++ b/app/routes/_layout+/kits.$kitId.assets.release-custody.tsx @@ -10,6 +10,7 @@ import { db } from "~/database/db.server"; import { useUserRoleHelper } from "~/hooks/user-user-role-helper"; import { getKit, releaseCustody } from "~/modules/kit/service.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError, ShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; @@ -21,6 +22,8 @@ import { import { requirePermission } from "~/utils/roles.server"; import { resolveTeamMemberName } from "~/utils/user"; +export const meta = () => [{ title: appendToMetaTitle("Release kit custody") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/kits.$kitId.assets.tsx b/app/routes/_layout+/kits.$kitId.assets.tsx index 8400656a6..3dce814b0 100644 --- a/app/routes/_layout+/kits.$kitId.assets.tsx +++ b/app/routes/_layout+/kits.$kitId.assets.tsx @@ -1,4 +1,4 @@ -import { data, type LoaderFunctionArgs } from "react-router"; +import { data, type LoaderFunctionArgs, type MetaFunction } from "react-router"; import { z } from "zod"; import { AssetImage } from "~/components/assets/asset-image"; import { AssetStatusBadge } from "~/components/assets/asset-status-badge"; @@ -19,6 +19,7 @@ import When from "~/components/when/when"; import { useUserRoleHelper } from "~/hooks/user-user-role-helper"; import { getAssetsForKits } from "~/modules/kit/service.server"; import type { ListItemForKitPage } from "~/modules/kit/types"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error, getParams } from "~/utils/http.server"; import { @@ -28,6 +29,10 @@ import { import { userHasPermission } from "~/utils/permissions/permission.validator.client"; import { requirePermission } from "~/utils/roles.server"; +export const meta: MetaFunction = ({ data }) => [ + { title: data ? appendToMetaTitle(data.header.title) : "" }, +]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const { userId } = context.getSession(); const { kitId } = getParams(params, z.object({ kitId: z.string() })); diff --git a/app/routes/_layout+/kits.$kitId.assets.update-location.tsx b/app/routes/_layout+/kits.$kitId.assets.update-location.tsx index 971fe13c1..6c109988b 100644 --- a/app/routes/_layout+/kits.$kitId.assets.update-location.tsx +++ b/app/routes/_layout+/kits.$kitId.assets.update-location.tsx @@ -7,6 +7,7 @@ import { Button } from "~/components/shared/button"; import { useDisabled } from "~/hooks/use-disabled"; import { getLocationsForCreateAndEdit } from "~/modules/asset/service.server"; import { getKit, updateKitLocation } from "~/modules/kit/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError } from "~/utils/error"; import { payload, getParams, parseData } from "~/utils/http.server"; @@ -16,6 +17,8 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Update kit location") }]; + const ParamsSchema = z.object({ kitId: z.string() }); const UpdateLocationSchema = z.object({ diff --git a/app/routes/_layout+/kits.$kitId.bookings.tsx b/app/routes/_layout+/kits.$kitId.bookings.tsx index 9fd8c06d5..919660c21 100644 --- a/app/routes/_layout+/kits.$kitId.bookings.tsx +++ b/app/routes/_layout+/kits.$kitId.bookings.tsx @@ -1,11 +1,12 @@ import { BookingStatus } from "@prisma/client"; -import { data, type LoaderFunctionArgs } from "react-router"; +import { data, type LoaderFunctionArgs, type MetaFunction } from "react-router"; import { z } from "zod"; import type { HeaderData } from "~/components/layout/header/types"; import { hasGetAllValue } from "~/hooks/use-model-filters"; import { getBookings } from "~/modules/booking/service.server"; import { getTagsForBookingTagsFilter } from "~/modules/tag/service.server"; import { getTeamMemberForCustodianFilter } from "~/modules/team-member/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { updateCookieWithPerPage } from "~/utils/cookies.server"; import { makeShelfError } from "~/utils/error"; import { @@ -33,6 +34,10 @@ const BOOKING_STATUS_TO_SHOW = [ BookingStatus.RESERVED, ]; +export const meta: MetaFunction = ({ data }) => [ + { title: data ? appendToMetaTitle(data.header.title) : "" }, +]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const { userId } = context.getSession(); const { kitId } = getParams(params, z.object({ kitId: z.string() })); diff --git a/app/routes/_layout+/kits.tsx b/app/routes/_layout+/kits.tsx index d81899c13..bfa0d4fb4 100644 --- a/app/routes/_layout+/kits.tsx +++ b/app/routes/_layout+/kits.tsx @@ -1,5 +1,8 @@ import { Link, Outlet } from "react-router"; import { ErrorContent } from "~/components/errors"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; + +export const meta = () => [{ title: appendToMetaTitle("Kits") }]; export function loader() { return null; diff --git a/app/routes/_layout+/locations.$locationId.assets.manage-assets.tsx b/app/routes/_layout+/locations.$locationId.assets.manage-assets.tsx index 7b46fb6f1..c087e5cea 100644 --- a/app/routes/_layout+/locations.$locationId.assets.manage-assets.tsx +++ b/app/routes/_layout+/locations.$locationId.assets.manage-assets.tsx @@ -1,7 +1,11 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { AssetStatus, type Prisma } from "@prisma/client"; import { useAtomValue, useSetAtom } from "jotai"; -import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router"; +import type { + ActionFunctionArgs, + LoaderFunctionArgs, + MetaFunction, +} from "react-router"; import { data, redirect, @@ -45,6 +49,7 @@ import { db } from "~/database/db.server"; import type { LOCATION_WITH_HIERARCHY } from "~/modules/asset/fields"; import { getPaginatedAndFilterableAssets } from "~/modules/asset/service.server"; import { updateLocationAssets } from "~/modules/location/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { ShelfError, makeShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; import { payload, error, getParams, parseData } from "~/utils/http.server"; @@ -55,6 +60,10 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta: MetaFunction = ({ data }) => [ + { title: appendToMetaTitle(data?.header.title) }, +]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; @@ -121,13 +130,14 @@ export async function loader({ context, request, params }: LoaderFunctionArgs) { singular: "asset", plural: "assets", }; + const header = { + title: `Move assets to ‘${location?.name}’ location`, + subHeading: + "Search your database for assets that you would like to move to this location.", + }; return payload({ - header: { - title: `Move assets to ‘${location?.name}’ location`, - subHeading: - "Search your database for assets that you would like to move to this location.", - }, + header, showSidebar: true, noScroll: true, items: assets, diff --git a/app/routes/_layout+/locations.$locationId.assets.tsx b/app/routes/_layout+/locations.$locationId.assets.tsx index 01e7a06a8..a940c583f 100644 --- a/app/routes/_layout+/locations.$locationId.assets.tsx +++ b/app/routes/_layout+/locations.$locationId.assets.tsx @@ -1,5 +1,5 @@ import type { Asset, Category, Tag, Location } from "@prisma/client"; -import type { LoaderFunctionArgs } from "react-router"; +import type { LoaderFunctionArgs, MetaFunction } from "react-router"; import { data, useLoaderData } from "react-router"; import z from "zod"; import { AssetImage } from "~/components/assets/asset-image"; @@ -19,6 +19,7 @@ import { Td, Th } from "~/components/table"; import When from "~/components/when/when"; import { useUserRoleHelper } from "~/hooks/user-user-role-helper"; import { getLocation } from "~/modules/location/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { updateCookieWithPerPage } from "~/utils/cookies.server"; import { makeShelfError } from "~/utils/error"; import { @@ -37,6 +38,10 @@ import { requirePermission } from "~/utils/roles.server"; const paramsSchema = z.object({ locationId: z.string() }); +export const meta: MetaFunction = ({ data }) => [ + { title: data ? appendToMetaTitle(data.header.title) : "" }, +]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const { userId } = context.getSession(); const { locationId } = getParams(params, paramsSchema); diff --git a/app/routes/_layout+/locations.$locationId.kits.tsx b/app/routes/_layout+/locations.$locationId.kits.tsx index 90fa08aef..f901ae000 100644 --- a/app/routes/_layout+/locations.$locationId.kits.tsx +++ b/app/routes/_layout+/locations.$locationId.kits.tsx @@ -1,5 +1,5 @@ import type { Prisma } from "@prisma/client"; -import type { LoaderFunctionArgs } from "react-router"; +import type { LoaderFunctionArgs, MetaFunction } from "react-router"; import { data, useParams } from "react-router"; import z from "zod"; import { CategoryBadge } from "~/components/assets/category-badge"; @@ -16,6 +16,7 @@ import { Td, Th } from "~/components/table"; import When from "~/components/when/when"; import { useUserRoleHelper } from "~/hooks/user-user-role-helper"; import { getLocationKits } from "~/modules/location/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { updateCookieWithPerPage } from "~/utils/cookies.server"; import { makeShelfError } from "~/utils/error"; import { @@ -34,6 +35,10 @@ import { requirePermission } from "~/utils/roles.server"; const paramsSchema = z.object({ locationId: z.string() }); +export const meta: MetaFunction = ({ loaderData }) => [ + { title: loaderData ? appendToMetaTitle(loaderData.header.title) : "" }, +]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const { userId } = context.getSession(); const { locationId } = getParams(params, paramsSchema); diff --git a/app/routes/_layout+/locations.tsx b/app/routes/_layout+/locations.tsx index b34cedb39..873bb38a2 100644 --- a/app/routes/_layout+/locations.tsx +++ b/app/routes/_layout+/locations.tsx @@ -1,6 +1,7 @@ import type { LoaderFunctionArgs } from "react-router"; import { Link, Outlet, data } from "react-router"; import { ErrorContent } from "~/components/errors"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error } from "~/utils/http.server"; import { @@ -9,6 +10,8 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Locations") }]; + export async function loader({ context, request }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/me.assets.tsx b/app/routes/_layout+/me.assets.tsx index 15f84abc3..4c883707b 100644 --- a/app/routes/_layout+/me.assets.tsx +++ b/app/routes/_layout+/me.assets.tsx @@ -1,6 +1,7 @@ import { data, type LoaderFunctionArgs } from "react-router"; import { AssetsList } from "~/components/assets/assets-index/assets-list"; import { getUserAssetsTabLoaderData } from "~/modules/asset/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error } from "~/utils/http.server"; import { @@ -15,6 +16,7 @@ import { requirePermission } from "~/utils/roles.server"; export const handle = { name: "me.assets", }; +export const meta = () => [{ title: appendToMetaTitle("My assets") }]; export async function loader({ request, context }: LoaderFunctionArgs) { const authSession = context.getSession(); diff --git a/app/routes/_layout+/me.bookings.tsx b/app/routes/_layout+/me.bookings.tsx index aa367872e..2f73f4895 100644 --- a/app/routes/_layout+/me.bookings.tsx +++ b/app/routes/_layout+/me.bookings.tsx @@ -1,8 +1,11 @@ +import type { MetaFunction } from "react-router"; import { data, type LoaderFunctionArgs } from "react-router"; import type { HeaderData } from "~/components/layout/header/types"; import { getBookings } from "~/modules/booking/service.server"; import { getTagsForBookingTagsFilter } from "~/modules/tag/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { updateCookieWithPerPage } from "~/utils/cookies.server"; + import { makeShelfError } from "~/utils/error"; import { payload, error, getCurrentSearchParams } from "~/utils/http.server"; import { getParamsValues } from "~/utils/list"; @@ -64,7 +67,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { const totalPages = Math.ceil(bookingCount / perPage); - const header: HeaderData = { title: "Bookings" }; + const header: HeaderData = { title: "My bookings" }; const modelName = { singular: "booking", @@ -93,6 +96,9 @@ export async function loader({ context, request }: LoaderFunctionArgs) { throw data(error(reason), { status: reason.status }); } } +export const meta: MetaFunction = ({ loaderData }) => [ + { title: appendToMetaTitle(loaderData?.header.title) }, +]; export default function MyBookings() { return ; diff --git a/app/routes/_layout+/reminders.tsx b/app/routes/_layout+/reminders.tsx index 2b8a5b70f..b2e3f07cf 100644 --- a/app/routes/_layout+/reminders.tsx +++ b/app/routes/_layout+/reminders.tsx @@ -1,5 +1,8 @@ import { Link, Outlet } from "react-router"; import { ErrorContent } from "~/components/errors"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; + +export const meta = () => [{ title: appendToMetaTitle("Reminders") }]; export function loader() { return null; diff --git a/app/routes/_layout+/settings.custom-fields.tsx b/app/routes/_layout+/settings.custom-fields.tsx index d38075857..00624ef9a 100644 --- a/app/routes/_layout+/settings.custom-fields.tsx +++ b/app/routes/_layout+/settings.custom-fields.tsx @@ -6,6 +6,7 @@ import { softDeleteCustomField, getCustomField, } from "~/modules/custom-field/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { ShelfError, makeShelfError } from "~/utils/error"; import { payload, error, parseData } from "~/utils/http.server"; @@ -16,6 +17,10 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [ + { title: appendToMetaTitle("Custom fields settings") }, +]; + export async function loader({ context, request }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/settings.team.nrm.$nrmId.edit.tsx b/app/routes/_layout+/settings.team.nrm.$nrmId.edit.tsx index cd50528e6..b9b20c1e4 100644 --- a/app/routes/_layout+/settings.team.nrm.$nrmId.edit.tsx +++ b/app/routes/_layout+/settings.team.nrm.$nrmId.edit.tsx @@ -8,6 +8,7 @@ import { } from "react-router"; import { useZorm } from "react-zorm"; import { z } from "zod"; + import { Form } from "~/components/custom-form"; import Input from "~/components/forms/input"; import { UserIcon } from "~/components/icons/library"; @@ -15,6 +16,7 @@ import { Button } from "~/components/shared/button"; import { db } from "~/database/db.server"; import { getTeamMember } from "~/modules/team-member/service.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; @@ -50,6 +52,7 @@ export async function loader({ context, request, params }: LoaderFunctionArgs) { throw data(error(reason), { status: reason.status }); } } +export const meta = () => [{ title: appendToMetaTitle("Edit team member") }]; export async function action({ context, request, params }: ActionFunctionArgs) { const authSession = context.getSession(); diff --git a/app/routes/_layout+/settings.team.nrm.add-member.tsx b/app/routes/_layout+/settings.team.nrm.add-member.tsx index bca303b9f..18d92d045 100644 --- a/app/routes/_layout+/settings.team.nrm.add-member.tsx +++ b/app/routes/_layout+/settings.team.nrm.add-member.tsx @@ -8,6 +8,8 @@ import { UserIcon } from "~/components/icons/library"; import { Button } from "~/components/shared/button"; import { db } from "~/database/db.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; + import { sendNotification } from "~/utils/emitter/send-notification.server"; import { makeShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; @@ -17,6 +19,7 @@ import { PermissionEntity, } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Add team member") }]; export async function loader({ context, request }: LoaderFunctionArgs) { const authSession = context.getSession(); diff --git a/app/routes/_layout+/settings.team.nrm.import-members.tsx b/app/routes/_layout+/settings.team.nrm.import-members.tsx index 050b5abdb..8d1d5d050 100644 --- a/app/routes/_layout+/settings.team.nrm.import-members.tsx +++ b/app/routes/_layout+/settings.team.nrm.import-members.tsx @@ -20,6 +20,7 @@ import { WarningBox } from "~/components/shared/warning-box"; import type { CreateAssetFromContentImportPayload } from "~/modules/asset/types"; import { createTeamMemberIfNotExists } from "~/modules/team-member/service.server"; import styles from "~/styles/layout/custom-modal.css?url"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; import { payload, error } from "~/utils/http.server"; @@ -30,6 +31,8 @@ import { import { requirePermission } from "~/utils/roles.server"; import { assertUserCanImportNRM } from "~/utils/subscription.server"; +export const meta = () => [{ title: appendToMetaTitle("Import team members") }]; + export async function loader({ context, request }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/settings.team.tsx b/app/routes/_layout+/settings.team.tsx index 3c0c7df06..2175f5087 100644 --- a/app/routes/_layout+/settings.team.tsx +++ b/app/routes/_layout+/settings.team.tsx @@ -5,6 +5,7 @@ import { ErrorContent } from "~/components/errors"; import HorizontalTabs from "~/components/layout/horizontal-tabs"; import type { Item } from "~/components/layout/horizontal-tabs/types"; import When from "~/components/when/when"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error } from "~/utils/http.server"; import { @@ -18,6 +19,7 @@ export type UserFriendlyRoles = | "Owner" | "Base" | "Self service"; +export const meta = () => [{ title: appendToMetaTitle("Team settings") }]; export const loader = async ({ request, context }: LoaderFunctionArgs) => { const authSession = context.getSession(); diff --git a/app/routes/_layout+/settings.team.users.$userId.assets.tsx b/app/routes/_layout+/settings.team.users.$userId.assets.tsx index cdef2d447..97692a377 100644 --- a/app/routes/_layout+/settings.team.users.$userId.assets.tsx +++ b/app/routes/_layout+/settings.team.users.$userId.assets.tsx @@ -3,6 +3,7 @@ import type { LoaderFunctionArgs } from "react-router"; import { z } from "zod"; import { AssetsList } from "~/components/assets/assets-index/assets-list"; import { getUserAssetsTabLoaderData } from "~/modules/asset/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { makeShelfError } from "~/utils/error"; import { payload, error, getParams } from "~/utils/http.server"; import { @@ -11,6 +12,8 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Team member assets") }]; + export async function loader({ request, context, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/_layout+/settings.team.users.$userId.bookings.tsx b/app/routes/_layout+/settings.team.users.$userId.bookings.tsx index 461c62ba1..d1d18089d 100644 --- a/app/routes/_layout+/settings.team.users.$userId.bookings.tsx +++ b/app/routes/_layout+/settings.team.users.$userId.bookings.tsx @@ -1,8 +1,10 @@ +import type { MetaFunction } from "react-router"; import { data, type LoaderFunctionArgs } from "react-router"; import { z } from "zod"; import type { HeaderData } from "~/components/layout/header/types"; import { getBookings } from "~/modules/booking/service.server"; import { getTagsForBookingTagsFilter } from "~/modules/tag/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { setCookie, updateCookieWithPerPage, @@ -26,6 +28,10 @@ import BookingsIndexPage, { bookingsSearchFieldTooltipText, } from "./bookings._index"; +export const meta: MetaFunction = ({ loaderData }) => [ + { title: appendToMetaTitle(loaderData?.header?.title) }, +]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; @@ -82,7 +88,7 @@ export async function loader({ context, request, params }: LoaderFunctionArgs) { const totalPages = Math.ceil(bookingCount / perPage); const header: HeaderData = { - title: "Bookings", + title: "Team member bookings", }; const modelName = { singular: "booking", diff --git a/app/routes/_welcome+/_layout.tsx b/app/routes/_welcome+/_layout.tsx index 879b03565..b6616d24f 100644 --- a/app/routes/_welcome+/_layout.tsx +++ b/app/routes/_welcome+/_layout.tsx @@ -1,6 +1,9 @@ import { Outlet } from "react-router"; import { ErrorContent } from "~/components/errors"; import { useCrisp } from "~/components/marketing/crisp"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; + +export const meta = () => [{ title: appendToMetaTitle("Welcome") }]; export default function OnboardingLayout() { useCrisp(); diff --git a/app/routes/barcode+/$value.tsx b/app/routes/barcode+/$value.tsx index 5168ea428..c85d00df7 100644 --- a/app/routes/barcode+/$value.tsx +++ b/app/routes/barcode+/$value.tsx @@ -5,6 +5,7 @@ import { z } from "zod"; import { ErrorContent } from "~/components/errors"; import { getBarcodeByValue } from "~/modules/barcode/service.server"; import { setSelectedOrganizationIdCookie } from "~/modules/organization/context.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { setCookie } from "~/utils/cookies.server"; import { makeShelfError, ShelfError } from "~/utils/error"; import { error, getParams } from "~/utils/http.server"; @@ -14,6 +15,8 @@ import { } from "~/utils/permissions/permission.data"; import { requirePermission } from "~/utils/roles.server"; +export const meta = () => [{ title: appendToMetaTitle("Barcode") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.getSession(); const { userId } = authSession; diff --git a/app/routes/qr+/$qrId.tsx b/app/routes/qr+/$qrId.tsx index a379e8da8..abe003292 100644 --- a/app/routes/qr+/$qrId.tsx +++ b/app/routes/qr+/$qrId.tsx @@ -7,6 +7,7 @@ import { setSelectedOrganizationIdCookie } from "~/modules/organization/context. import { getUserOrganizations } from "~/modules/organization/service.server"; import { getQr } from "~/modules/qr/service.server"; import { createScan, updateScan } from "~/modules/scan/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { setCookie } from "~/utils/cookies.server"; import { makeShelfError, ShelfError } from "~/utils/error"; import { @@ -17,6 +18,8 @@ import { parseData, } from "~/utils/http.server"; +export const meta = () => [{ title: appendToMetaTitle("QR code") }]; + export async function loader({ context, request, params }: LoaderFunctionArgs) { const authSession = context.isAuthenticated ? context.getSession() diff --git a/app/routes/qr+/$qrId_.contact-owner.tsx b/app/routes/qr+/$qrId_.contact-owner.tsx index a97299492..e5ecaa0c8 100644 --- a/app/routes/qr+/$qrId_.contact-owner.tsx +++ b/app/routes/qr+/$qrId_.contact-owner.tsx @@ -12,6 +12,7 @@ import { createReport, sendReportEmails, } from "~/modules/report-found/service.server"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { ShelfError, makeShelfError } from "~/utils/error"; import { isFormProcessing } from "~/utils/form"; import { @@ -23,6 +24,8 @@ import { } from "~/utils/http.server"; import { tw } from "~/utils/tw"; +export const meta = () => [{ title: appendToMetaTitle("Contact owner") }]; + export const NewReportSchema = z.object({ email: z .string() diff --git a/app/routes/qr+/$qrId_.not-logged-in.tsx b/app/routes/qr+/$qrId_.not-logged-in.tsx index 3b53551ba..718182d6c 100644 --- a/app/routes/qr+/$qrId_.not-logged-in.tsx +++ b/app/routes/qr+/$qrId_.not-logged-in.tsx @@ -5,8 +5,11 @@ import { CuboidIcon } from "~/components/icons/library"; import { Button } from "~/components/shared/button"; import { useSearchParams } from "~/hooks/search-params"; import { usePosition } from "~/hooks/use-position"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; import { payload, getParams } from "~/utils/http.server"; +export const meta = () => [{ title: appendToMetaTitle("QR not logged in") }]; + export function loader({ params }: LoaderFunctionArgs) { const { qrId } = getParams(params, z.object({ qrId: z.string() })); diff --git a/app/routes/qr+/route.tsx b/app/routes/qr+/route.tsx index 9bd6762cb..5aee9b326 100644 --- a/app/routes/qr+/route.tsx +++ b/app/routes/qr+/route.tsx @@ -2,6 +2,9 @@ import { Link, Outlet } from "react-router"; import { ErrorContent } from "~/components/errors"; import { ShelfFullLogo } from "~/components/marketing/logos"; import { usePosition } from "~/hooks/use-position"; +import { appendToMetaTitle } from "~/utils/append-to-meta-title"; + +export const meta = () => [{ title: appendToMetaTitle("QR codes") }]; export default function QR() { usePosition(); diff --git a/eslint-local-rules.cjs b/eslint-local-rules.cjs index d06916199..de9445f06 100644 --- a/eslint-local-rules.cjs +++ b/eslint-local-rules.cjs @@ -2,6 +2,6 @@ module.exports = { "require-satisfies-on-nested-prisma-selects": require("./eslint-local-rules/require-satisfies-on-nested-prisma-selects.cjs"), "require-deleted-at-check-on-custom-field-queries": require("./eslint-local-rules/require-deleted-at-check-on-custom-field-queries.cjs"), + "require-meta-export-in-routes": require("./eslint-local-rules/require-meta-export-in-routes.cjs"), "require-react-import-when-using-namespace": require("./eslint-local-rules/require-react-import-when-using-namespace.cjs"), - // "require-meta-export-in-routes": require("./eslint-local-rules/require-meta-export-in-routes.cjs"), }; diff --git a/eslint-local-rules/require-meta-export-in-routes.cjs b/eslint-local-rules/require-meta-export-in-routes.cjs index 1dfb77024..128e574b8 100644 --- a/eslint-local-rules/require-meta-export-in-routes.cjs +++ b/eslint-local-rules/require-meta-export-in-routes.cjs @@ -43,13 +43,13 @@ module.exports = { } let hasMetaExport = false; - let hasLoaderOrAction = false; let hasDefaultExport = false; return { ExportNamedDeclaration(node) { // Check if this is a meta export if (node.declaration) { + // Check for: export const meta = ... if ( node.declaration.type === "VariableDeclaration" && node.declaration.declarations.some( @@ -57,17 +57,18 @@ module.exports = { ) ) { hasMetaExport = true; - } else if ( + } + // Check for: export function meta(...) { ... } + else if ( node.declaration.type === "FunctionDeclaration" && node.declaration.id && - (node.declaration.id.name === "loader" || - node.declaration.id.name === "action") + node.declaration.id.name === "meta" ) { - hasLoaderOrAction = true; + hasMetaExport = true; } } - // Handle export const meta = ... + // Handle: export { meta } if ( node.specifiers && node.specifiers.some( @@ -79,11 +80,6 @@ module.exports = { } }, - // Check for export function loader/action - ExportAllDeclaration() { - // Not relevant for this rule - }, - // Check for default export (component) ExportDefaultDeclaration() { hasDefaultExport = true; @@ -91,9 +87,9 @@ module.exports = { // At the end of the file, check if meta export exists "Program:exit"(node) { - // Only warn if this is a route file with a component or loader/action - // Skip if no default export and no loader/action (likely not a route file) - if (!hasDefaultExport && !hasLoaderOrAction) { + // Only warn if this is a route file with a default export (page component) + // Resource routes (without default export) don't need meta tags + if (!hasDefaultExport) { return; }