diff --git a/apps/webapp/app/components/Header.tsx b/apps/webapp/app/components/Header.tsx index 0183d0bed..76d7857e4 100644 --- a/apps/webapp/app/components/Header.tsx +++ b/apps/webapp/app/components/Header.tsx @@ -2,6 +2,7 @@ import { DocumentTextIcon } from "@heroicons/react/24/solid"; import { Link } from "@remix-run/react"; import { useOptionalUser } from "~/hooks/useUser"; import { Logo } from "./Logo"; +import { OrganizationMenu } from "./navigation/OrganizationMenu"; import { UserProfileMenu } from "./UserProfileMenu"; type HeaderProps = { @@ -17,6 +18,8 @@ export function Header({ children }: HeaderProps) { + +
{children}
diff --git a/apps/webapp/app/components/navigation/OrganizationMenu.tsx b/apps/webapp/app/components/navigation/OrganizationMenu.tsx new file mode 100644 index 000000000..d2ebff757 --- /dev/null +++ b/apps/webapp/app/components/navigation/OrganizationMenu.tsx @@ -0,0 +1,114 @@ +import { Organization } from ".prisma/client"; +import { Popover, Transition } from "@headlessui/react"; +import { + BookmarkIcon, + BriefcaseIcon, + CheckIcon, + ChevronDownIcon, + PlusIcon, +} from "@heroicons/react/24/solid"; +import { Link } from "@remix-run/react"; +import classNames from "classnames"; +import React, { Fragment } from "react"; +import { + useCurrentOrganizationSlug, + useOrganizations, +} from "~/hooks/useOrganizations"; + +const actionClassNames = "text-green-500"; + +export function OrganizationMenu() { + const organizations = useOrganizations(); + const currentOrganizationSlug = useCurrentOrganizationSlug(); + + const currentOrganization = organizations?.find( + (org) => org.slug === currentOrganizationSlug + ); + + if (organizations === undefined) { + return null; + } + + return ( +
+ + {({ open }) => ( + <> + + + {currentOrganization ? ( + {currentOrganization.title} + ) : ( + + Create new Organization + + )} + + + + +
+
+ {organizations.map((organization) => { + return ( + +
+
+ {organization.slug === currentOrganizationSlug && ( + + )} +
+ ); + })} + +
+
+
+
+
+
+
+ + )} +
+
+ ); +} diff --git a/apps/webapp/app/hooks/useOrganizations.ts b/apps/webapp/app/hooks/useOrganizations.ts index e104176c8..c7918c758 100644 --- a/apps/webapp/app/hooks/useOrganizations.ts +++ b/apps/webapp/app/hooks/useOrganizations.ts @@ -15,10 +15,15 @@ function isOrganizations(orgs: any): orgs is Organization[] { } export function useOrganizations(): Organization[] | undefined { - const data = useMatchesData("routes/__app"); + const routeMatch = useMatchesData("routes/__app"); - if (!data || !isOrganizations(data.organizations)) { + if (!routeMatch || !isOrganizations(routeMatch.data.organizations)) { return undefined; } - return data.organizations; + return routeMatch.data.organizations; +} + +export function useCurrentOrganizationSlug(): string | undefined { + const routeMatch = useMatchesData("routes/__app/orgs/$organizationSlug"); + return routeMatch?.params?.organizationSlug; } diff --git a/apps/webapp/app/hooks/useUser.ts b/apps/webapp/app/hooks/useUser.ts index 772fd34ac..882ceaece 100644 --- a/apps/webapp/app/hooks/useUser.ts +++ b/apps/webapp/app/hooks/useUser.ts @@ -6,11 +6,11 @@ function isUser(user: any): user is User { } export function useOptionalUser(): User | undefined { - const data = useMatchesData("root"); - if (!data || !isUser(data.user)) { + const routeMatch = useMatchesData("root"); + if (!routeMatch || !isUser(routeMatch.data.user)) { return undefined; } - return data.user; + return routeMatch.data.user; } export function useUser(): User { diff --git a/apps/webapp/app/routes/__app/index.tsx b/apps/webapp/app/routes/__app/index.tsx index c37c1393e..0db6bcf21 100644 --- a/apps/webapp/app/routes/__app/index.tsx +++ b/apps/webapp/app/routes/__app/index.tsx @@ -9,7 +9,7 @@ export default function AppLayout() { return ( <> -
Home
+
    diff --git a/apps/webapp/app/routes/__app/orgs/$organizationSlug.tsx b/apps/webapp/app/routes/__app/orgs/$organizationSlug.tsx index 8368bb36f..94cc29010 100644 --- a/apps/webapp/app/routes/__app/orgs/$organizationSlug.tsx +++ b/apps/webapp/app/routes/__app/orgs/$organizationSlug.tsx @@ -25,7 +25,6 @@ export const loader = async ({ request, params }: LoaderArgs) => { export default function Organization() { return ( <> - Organizations ); diff --git a/apps/webapp/app/routes/__app/orgs/$organizationSlug/index.tsx b/apps/webapp/app/routes/__app/orgs/$organizationSlug/index.tsx index e987aa8f9..083b6b4ab 100644 --- a/apps/webapp/app/routes/__app/orgs/$organizationSlug/index.tsx +++ b/apps/webapp/app/routes/__app/orgs/$organizationSlug/index.tsx @@ -1,3 +1,11 @@ +import { Header } from "~/components/Header"; +import { AppBody } from "~/components/layout/AppLayout"; + export default function OrganizationBlankState() { - return <>You need to create a workflow; + return ( + <> +
    + You need to create a workflow + + ); } diff --git a/apps/webapp/app/utils.ts b/apps/webapp/app/utils.ts index 29980f988..0afdfeedd 100644 --- a/apps/webapp/app/utils.ts +++ b/apps/webapp/app/utils.ts @@ -1,3 +1,4 @@ +import type { RouteMatch } from "@remix-run/react"; import { useMatches } from "@remix-run/react"; import { useMemo } from "react"; @@ -34,7 +35,7 @@ export function safeRedirect( export function useMatchesData( id: string, debug: boolean = false -): Record | undefined { +): RouteMatch | undefined { const matchingRoutes = useMatches(); if (debug) { console.log("matchingRoutes", matchingRoutes); @@ -44,7 +45,7 @@ export function useMatchesData( () => matchingRoutes.find((route) => route.id === id), [matchingRoutes, id] ); - return route?.data; + return route; } export function validateEmail(email: unknown): email is string {