From 48396d08fb7a72a8e271c123600916ff1af358e8 Mon Sep 17 00:00:00 2001 From: cade Date: Fri, 29 Nov 2024 12:56:38 -0800 Subject: [PATCH] add page breadcrumb --- .../share/[subjectId]/layout.tsx | 0 .../share/[subjectId]}/loading.tsx | 3 +- .../{ => (empty)}/share/[subjectId]/page.tsx | 0 .../subjects/[subjectId]/events.csv/route.ts | 0 .../[subjectId]/join/[shareCode]/page.tsx | 0 app/(pages)/(menu)/inbox/loading.tsx | 11 + app/(pages)/(menu)/inbox/page.tsx | 22 ++ app/(pages)/(menu)/inputs/loading.tsx | 11 + app/(pages)/(menu)/inputs/page.tsx | 18 ++ app/(pages)/{(with-nav) => (menu)}/layout.tsx | 72 +++--- .../(menu)/subjects/[subjectId]/loading.tsx | 11 + .../subjects/[subjectId]/page.tsx | 0 app/(pages)/(menu)/subjects/loading.tsx | 11 + .../{(with-nav) => (menu)}/subjects/page.tsx | 3 +- app/(pages)/(menu)/templates/loading.tsx | 11 + app/(pages)/(menu)/templates/page.tsx | 20 ++ app/(pages)/(with-nav)/inbox/layout.tsx | 14 -- app/(pages)/(with-nav)/inbox/loading.tsx | 5 - app/(pages)/(with-nav)/inbox/page.tsx | 9 - app/(pages)/(with-nav)/inputs/layout.tsx | 14 -- app/(pages)/(with-nav)/inputs/loading.tsx | 5 - app/(pages)/(with-nav)/inputs/page.tsx | 26 -- app/(pages)/(with-nav)/loading.tsx | 3 - .../subjects/[subjectId]/loading.tsx | 3 - app/(pages)/(with-nav)/templates/layout.tsx | 14 -- app/(pages)/(with-nav)/templates/loading.tsx | 5 - app/(pages)/(with-nav)/templates/page.tsx | 28 --- app/(pages)/share/[subjectId]/loading.tsx | 3 - app/_components/account-menu.tsx | 1 + app/_components/breadcrumb.tsx | 98 ++++++++ app/_components/filterable-inputs.tsx | 13 + app/_components/filterable-templates.tsx | 13 + app/_components/page-breadcrumb.tsx | 49 ++++ app/_components/subject-loading.tsx | 13 - app/_components/subject-page.tsx | 222 ++++++++++-------- 35 files changed, 449 insertions(+), 282 deletions(-) rename app/(pages)/{ => (empty)}/share/[subjectId]/layout.tsx (100%) rename app/(pages)/{(with-nav)/subjects => (empty)/share/[subjectId]}/loading.tsx (61%) rename app/(pages)/{ => (empty)}/share/[subjectId]/page.tsx (100%) rename app/(pages)/{ => (empty)}/subjects/[subjectId]/events.csv/route.ts (100%) rename app/(pages)/{ => (empty)}/subjects/[subjectId]/join/[shareCode]/page.tsx (100%) create mode 100644 app/(pages)/(menu)/inbox/loading.tsx create mode 100644 app/(pages)/(menu)/inbox/page.tsx create mode 100644 app/(pages)/(menu)/inputs/loading.tsx create mode 100644 app/(pages)/(menu)/inputs/page.tsx rename app/(pages)/{(with-nav) => (menu)}/layout.tsx (100%) create mode 100644 app/(pages)/(menu)/subjects/[subjectId]/loading.tsx rename app/(pages)/{(with-nav) => (menu)}/subjects/[subjectId]/page.tsx (100%) create mode 100644 app/(pages)/(menu)/subjects/loading.tsx rename app/(pages)/{(with-nav) => (menu)}/subjects/page.tsx (96%) create mode 100644 app/(pages)/(menu)/templates/loading.tsx create mode 100644 app/(pages)/(menu)/templates/page.tsx delete mode 100644 app/(pages)/(with-nav)/inbox/layout.tsx delete mode 100644 app/(pages)/(with-nav)/inbox/loading.tsx delete mode 100644 app/(pages)/(with-nav)/inbox/page.tsx delete mode 100644 app/(pages)/(with-nav)/inputs/layout.tsx delete mode 100644 app/(pages)/(with-nav)/inputs/loading.tsx delete mode 100644 app/(pages)/(with-nav)/inputs/page.tsx delete mode 100644 app/(pages)/(with-nav)/loading.tsx delete mode 100644 app/(pages)/(with-nav)/subjects/[subjectId]/loading.tsx delete mode 100644 app/(pages)/(with-nav)/templates/layout.tsx delete mode 100644 app/(pages)/(with-nav)/templates/loading.tsx delete mode 100644 app/(pages)/(with-nav)/templates/page.tsx delete mode 100644 app/(pages)/share/[subjectId]/loading.tsx create mode 100644 app/_components/breadcrumb.tsx create mode 100644 app/_components/page-breadcrumb.tsx delete mode 100644 app/_components/subject-loading.tsx diff --git a/app/(pages)/share/[subjectId]/layout.tsx b/app/(pages)/(empty)/share/[subjectId]/layout.tsx similarity index 100% rename from app/(pages)/share/[subjectId]/layout.tsx rename to app/(pages)/(empty)/share/[subjectId]/layout.tsx diff --git a/app/(pages)/(with-nav)/subjects/loading.tsx b/app/(pages)/(empty)/share/[subjectId]/loading.tsx similarity index 61% rename from app/(pages)/(with-nav)/subjects/loading.tsx rename to app/(pages)/(empty)/share/[subjectId]/loading.tsx index e05fcd54..e609f86c 100644 --- a/app/(pages)/(with-nav)/subjects/loading.tsx +++ b/app/(pages)/(empty)/share/[subjectId]/loading.tsx @@ -1,8 +1,9 @@ +import PageBreadcrumb from '@/_components/page-breadcrumb'; import Spinner from '@/_components/spinner'; const Loading = () => ( <> -

Subjects

+ ); diff --git a/app/(pages)/share/[subjectId]/page.tsx b/app/(pages)/(empty)/share/[subjectId]/page.tsx similarity index 100% rename from app/(pages)/share/[subjectId]/page.tsx rename to app/(pages)/(empty)/share/[subjectId]/page.tsx diff --git a/app/(pages)/subjects/[subjectId]/events.csv/route.ts b/app/(pages)/(empty)/subjects/[subjectId]/events.csv/route.ts similarity index 100% rename from app/(pages)/subjects/[subjectId]/events.csv/route.ts rename to app/(pages)/(empty)/subjects/[subjectId]/events.csv/route.ts diff --git a/app/(pages)/subjects/[subjectId]/join/[shareCode]/page.tsx b/app/(pages)/(empty)/subjects/[subjectId]/join/[shareCode]/page.tsx similarity index 100% rename from app/(pages)/subjects/[subjectId]/join/[shareCode]/page.tsx rename to app/(pages)/(empty)/subjects/[subjectId]/join/[shareCode]/page.tsx diff --git a/app/(pages)/(menu)/inbox/loading.tsx b/app/(pages)/(menu)/inbox/loading.tsx new file mode 100644 index 00000000..e609f86c --- /dev/null +++ b/app/(pages)/(menu)/inbox/loading.tsx @@ -0,0 +1,11 @@ +import PageBreadcrumb from '@/_components/page-breadcrumb'; +import Spinner from '@/_components/spinner'; + +const Loading = () => ( + <> + + + +); + +export default Loading; diff --git a/app/(pages)/(menu)/inbox/page.tsx b/app/(pages)/(menu)/inbox/page.tsx new file mode 100644 index 00000000..8cbf29ea --- /dev/null +++ b/app/(pages)/(menu)/inbox/page.tsx @@ -0,0 +1,22 @@ +import Notifications from '@/_components/notifications'; +import PageBreadcrumb from '@/_components/page-breadcrumb'; +import getCurrentUser from '@/_queries/get-current-user'; +import listNotifications from '@/_queries/list-notifications'; + +const Page = async () => { + const [{ data: notifications }, user] = await Promise.all([ + listNotifications(), + getCurrentUser(), + ]); + + if (!notifications || !user) return null; + + return ( + <> + + + + ); +}; + +export default Page; diff --git a/app/(pages)/(menu)/inputs/loading.tsx b/app/(pages)/(menu)/inputs/loading.tsx new file mode 100644 index 00000000..e609f86c --- /dev/null +++ b/app/(pages)/(menu)/inputs/loading.tsx @@ -0,0 +1,11 @@ +import PageBreadcrumb from '@/_components/page-breadcrumb'; +import Spinner from '@/_components/spinner'; + +const Loading = () => ( + <> + + + +); + +export default Loading; diff --git a/app/(pages)/(menu)/inputs/page.tsx b/app/(pages)/(menu)/inputs/page.tsx new file mode 100644 index 00000000..f0cfd4b7 --- /dev/null +++ b/app/(pages)/(menu)/inputs/page.tsx @@ -0,0 +1,18 @@ +import FilterableInputs from '@/_components/filterable-inputs'; +import PageBreadcrumb from '@/_components/page-breadcrumb'; +import listInputsWithUses from '@/_queries/list-inputs-with-uses'; +import { sortBy } from 'lodash'; + +const Page = async () => { + const [{ data: inputs }] = await Promise.all([listInputsWithUses()]); + if (!inputs) return null; + + return ( + <> + + + + ); +}; + +export default Page; diff --git a/app/(pages)/(with-nav)/layout.tsx b/app/(pages)/(menu)/layout.tsx similarity index 100% rename from app/(pages)/(with-nav)/layout.tsx rename to app/(pages)/(menu)/layout.tsx index d2221e62..5188d59f 100644 --- a/app/(pages)/(with-nav)/layout.tsx +++ b/app/(pages)/(menu)/layout.tsx @@ -53,44 +53,8 @@ const Layout = async ({ children }: LayoutProps) => { Subjects - {!user.app_metadata.is_client && ( <> - - - } - label="Add new…" - variant="primary" - /> - - - - - Add new menu - - - - - diff --git a/app/(pages)/(menu)/subjects/[subjectId]/loading.tsx b/app/(pages)/(menu)/subjects/[subjectId]/loading.tsx new file mode 100644 index 00000000..e609f86c --- /dev/null +++ b/app/(pages)/(menu)/subjects/[subjectId]/loading.tsx @@ -0,0 +1,11 @@ +import PageBreadcrumb from '@/_components/page-breadcrumb'; +import Spinner from '@/_components/spinner'; + +const Loading = () => ( + <> + + + +); + +export default Loading; diff --git a/app/(pages)/(with-nav)/subjects/[subjectId]/page.tsx b/app/(pages)/(menu)/subjects/[subjectId]/page.tsx similarity index 100% rename from app/(pages)/(with-nav)/subjects/[subjectId]/page.tsx rename to app/(pages)/(menu)/subjects/[subjectId]/page.tsx diff --git a/app/(pages)/(menu)/subjects/loading.tsx b/app/(pages)/(menu)/subjects/loading.tsx new file mode 100644 index 00000000..e609f86c --- /dev/null +++ b/app/(pages)/(menu)/subjects/loading.tsx @@ -0,0 +1,11 @@ +import PageBreadcrumb from '@/_components/page-breadcrumb'; +import Spinner from '@/_components/spinner'; + +const Loading = () => ( + <> + + + +); + +export default Loading; diff --git a/app/(pages)/(with-nav)/subjects/page.tsx b/app/(pages)/(menu)/subjects/page.tsx similarity index 96% rename from app/(pages)/(with-nav)/subjects/page.tsx rename to app/(pages)/(menu)/subjects/page.tsx index bf1046f5..fd8edd36 100644 --- a/app/(pages)/(with-nav)/subjects/page.tsx +++ b/app/(pages)/(menu)/subjects/page.tsx @@ -1,5 +1,6 @@ import CollapsibleArchive from '@/_components/collapsible-archive'; import Empty from '@/_components/empty'; +import PageBreadcrumb from '@/_components/page-breadcrumb'; import SubjectList from '@/_components/subject-list'; import canInsertSubjectOnCurrentPlan from '@/_queries/can-insert-subject-on-current-plan'; import getCurrentUser from '@/_queries/get-current-user'; @@ -43,7 +44,7 @@ const Page = async () => { return ( <> -

Subjects

+
{!clientSubjects.length && !teamSubjects.length && ( diff --git a/app/(pages)/(menu)/templates/loading.tsx b/app/(pages)/(menu)/templates/loading.tsx new file mode 100644 index 00000000..e609f86c --- /dev/null +++ b/app/(pages)/(menu)/templates/loading.tsx @@ -0,0 +1,11 @@ +import PageBreadcrumb from '@/_components/page-breadcrumb'; +import Spinner from '@/_components/spinner'; + +const Loading = () => ( + <> + + + +); + +export default Loading; diff --git a/app/(pages)/(menu)/templates/page.tsx b/app/(pages)/(menu)/templates/page.tsx new file mode 100644 index 00000000..3b4d01cd --- /dev/null +++ b/app/(pages)/(menu)/templates/page.tsx @@ -0,0 +1,20 @@ +import FilterableTemplates from '@/_components/filterable-templates'; +import PageBreadcrumb from '@/_components/page-breadcrumb'; +import listTemplates from '@/_queries/list-templates'; +import { sortBy } from 'lodash'; + +const Page = async () => { + const [{ data: templates }] = await Promise.all([listTemplates()]); + if (!templates) return null; + + return ( + <> + + + + ); +}; + +export default Page; diff --git a/app/(pages)/(with-nav)/inbox/layout.tsx b/app/(pages)/(with-nav)/inbox/layout.tsx deleted file mode 100644 index d808b1b8..00000000 --- a/app/(pages)/(with-nav)/inbox/layout.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { ReactNode } from 'react'; - -interface PageProps { - children: ReactNode; -} - -const Layout = ({ children }: PageProps) => ( - <> -

Inbox

- {children} - -); - -export default Layout; diff --git a/app/(pages)/(with-nav)/inbox/loading.tsx b/app/(pages)/(with-nav)/inbox/loading.tsx deleted file mode 100644 index 8437b84e..00000000 --- a/app/(pages)/(with-nav)/inbox/loading.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import Spinner from '@/_components/spinner'; - -const Loading = () => ; - -export default Loading; diff --git a/app/(pages)/(with-nav)/inbox/page.tsx b/app/(pages)/(with-nav)/inbox/page.tsx deleted file mode 100644 index 6bacdddb..00000000 --- a/app/(pages)/(with-nav)/inbox/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import Notifications from '@/_components/notifications'; -import listNotifications from '@/_queries/list-notifications'; - -const Page = async () => { - const { data: notifications } = await listNotifications(); - return ; -}; - -export default Page; diff --git a/app/(pages)/(with-nav)/inputs/layout.tsx b/app/(pages)/(with-nav)/inputs/layout.tsx deleted file mode 100644 index 9d56435e..00000000 --- a/app/(pages)/(with-nav)/inputs/layout.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { ReactNode } from 'react'; - -interface LayoutProps { - children: ReactNode; -} - -const Layout = ({ children }: LayoutProps) => ( - <> -

Inputs

- {children} - -); - -export default Layout; diff --git a/app/(pages)/(with-nav)/inputs/loading.tsx b/app/(pages)/(with-nav)/inputs/loading.tsx deleted file mode 100644 index 8437b84e..00000000 --- a/app/(pages)/(with-nav)/inputs/loading.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import Spinner from '@/_components/spinner'; - -const Loading = () => ; - -export default Loading; diff --git a/app/(pages)/(with-nav)/inputs/page.tsx b/app/(pages)/(with-nav)/inputs/page.tsx deleted file mode 100644 index 183a07c0..00000000 --- a/app/(pages)/(with-nav)/inputs/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import Empty from '@/_components/empty'; -import FilterableInputs from '@/_components/filterable-inputs'; -import listInputsWithUses from '@/_queries/list-inputs-with-uses'; -import InformationCircleIcon from '@heroicons/react/24/outline/InformationCircleIcon'; -import { sortBy } from 'lodash'; - -const Page = async () => { - const { data: inputs } = await listInputsWithUses(); - - if (!inputs?.length) { - return ( - - - Inputs define the specific data points -
- you are interested in tracking. -
- ); - } - - return ( - - ); -}; - -export default Page; diff --git a/app/(pages)/(with-nav)/loading.tsx b/app/(pages)/(with-nav)/loading.tsx deleted file mode 100644 index b95ccc10..00000000 --- a/app/(pages)/(with-nav)/loading.tsx +++ /dev/null @@ -1,3 +0,0 @@ -const Loading = () => null; - -export default Loading; diff --git a/app/(pages)/(with-nav)/subjects/[subjectId]/loading.tsx b/app/(pages)/(with-nav)/subjects/[subjectId]/loading.tsx deleted file mode 100644 index e25c34a7..00000000 --- a/app/(pages)/(with-nav)/subjects/[subjectId]/loading.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import SubjectLoading from '@/_components/subject-loading'; - -export default SubjectLoading; diff --git a/app/(pages)/(with-nav)/templates/layout.tsx b/app/(pages)/(with-nav)/templates/layout.tsx deleted file mode 100644 index c7b313d5..00000000 --- a/app/(pages)/(with-nav)/templates/layout.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { ReactNode } from 'react'; - -interface LayoutProps { - children: ReactNode; -} - -const Layout = ({ children }: LayoutProps) => ( - <> -

Templates

- {children} - -); - -export default Layout; diff --git a/app/(pages)/(with-nav)/templates/loading.tsx b/app/(pages)/(with-nav)/templates/loading.tsx deleted file mode 100644 index 8437b84e..00000000 --- a/app/(pages)/(with-nav)/templates/loading.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import Spinner from '@/_components/spinner'; - -const Loading = () => ; - -export default Loading; diff --git a/app/(pages)/(with-nav)/templates/page.tsx b/app/(pages)/(with-nav)/templates/page.tsx deleted file mode 100644 index 1890d95b..00000000 --- a/app/(pages)/(with-nav)/templates/page.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import Empty from '@/_components/empty'; -import FilterableTemplates from '@/_components/filterable-templates'; -import listTemplates from '@/_queries/list-templates'; -import InformationCircleIcon from '@heroicons/react/24/outline/InformationCircleIcon'; -import { sortBy } from 'lodash'; - -const Page = async () => { - const { data: templates } = await listTemplates(); - - if (!templates?.length) { - return ( - - - Templates define reusable content -
- for event types and protocols. -
- ); - } - - return ( - - ); -}; - -export default Page; diff --git a/app/(pages)/share/[subjectId]/loading.tsx b/app/(pages)/share/[subjectId]/loading.tsx deleted file mode 100644 index e25c34a7..00000000 --- a/app/(pages)/share/[subjectId]/loading.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import SubjectLoading from '@/_components/subject-loading'; - -export default SubjectLoading; diff --git a/app/_components/account-menu.tsx b/app/_components/account-menu.tsx index c27f6781..7c70e335 100644 --- a/app/_components/account-menu.tsx +++ b/app/_components/account-menu.tsx @@ -84,6 +84,7 @@ const AccountMenu = ({ user, teams }: AccountMenuProps) => { onClick={(e) => { e.preventDefault(); setChangeTeamsId(team.id); + startChangeTeamsTransition(() => setActiveTeam(team.id), ); diff --git a/app/_components/breadcrumb.tsx b/app/_components/breadcrumb.tsx new file mode 100644 index 00000000..7049e629 --- /dev/null +++ b/app/_components/breadcrumb.tsx @@ -0,0 +1,98 @@ +import EllipsisHorizontalIcon from '@heroicons/react/24/outline/EllipsisHorizontalIcon'; +import SlashIcon from '@heroicons/react/24/outline/SlashIcon'; +import { Slot } from '@radix-ui/react-slot'; +import NextLink from 'next/link'; +import * as React from 'react'; +import { twMerge } from 'tailwind-merge'; + +const Ellipsis = ({ className, ...props }: React.ComponentProps<'span'>) => ( + +); + +Ellipsis.displayName = 'Ellipsis'; + +const Item = React.forwardRef< + HTMLLIElement, + React.ComponentPropsWithoutRef<'li'> +>(({ className, ...props }, ref) => ( +
  • +)); + +Item.displayName = 'Item'; + +const Link = React.forwardRef< + HTMLAnchorElement, + React.ComponentPropsWithoutRef & { + asChild?: boolean; + } +>(({ asChild, className, ...props }, ref) => { + const Comp = asChild ? Slot : NextLink; + return ; +}); + +Link.displayName = 'Link'; + +const List = React.forwardRef< + HTMLOListElement, + React.ComponentPropsWithoutRef<'ol'> +>(({ className, ...props }, ref) => ( +
      +)); + +List.displayName = 'List'; + +const Page = React.forwardRef< + HTMLSpanElement, + React.ComponentPropsWithoutRef<'span'> +>(({ className, ...props }, ref) => ( + +)); + +Page.displayName = 'Page'; + +const Root = React.forwardRef< + HTMLElement, + React.ComponentPropsWithoutRef<'nav'> & { + separator?: React.ReactNode; + } +>(({ ...props }, ref) =>