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) {
+
+
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.title}
+
+
+ {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 (
<>
-
+
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 {