From 3d3aca387eddb614cd5284d244ba168690b98f2e Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Tue, 18 Feb 2025 07:23:34 +1100 Subject: [PATCH 1/3] Add pending team invites notification to header navigation --- .../components/layout/header.component.tsx | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/web/components/layout/header.component.tsx b/apps/web/components/layout/header.component.tsx index bfcca07..906d7d0 100644 --- a/apps/web/components/layout/header.component.tsx +++ b/apps/web/components/layout/header.component.tsx @@ -7,7 +7,7 @@ import Head from "next/head"; import Image from "next/legacy/image"; import Link from "next/link"; import { useRouter } from "next/router"; -import { Fragment, useMemo } from "react"; +import { Fragment, useEffect, useMemo, useState } from "react"; import { DEFAULT_TITLE, SUBTITLE, TAGLINE } from "../../data/marketing.data"; import { ROUTES } from "../../data/routes.data"; import logoImage from "../../public/images/logo.png"; @@ -18,15 +18,29 @@ import { MenuItem } from "../core/menu.component"; import { createToastWrapper } from "../core/toast.component"; export default function HeaderComponent() { - const { loading, user, billingDetails, signOut } = useUserData(); + const { loading, user, billingDetails, signOut, supabase } = useUserData(); const router = useRouter(); const prefersColorScheme = usePrefersColorScheme(); + const [hasPendingInvites, setHasPendingInvites] = useState(false); + + useEffect(() => { + if (!user) return; + supabase + .from("team_invitations") + .select("id") + .eq("status", "pending") + .eq("email", user.email) + .then(({ data }) => { + setHasPendingInvites(data?.length > 0); + }); + }, [user]); + const navigation = useMemo(() => { if (user) { return [ { name: "Pages", href: ROUTES.PAGES }, - { name: "Teams", href: ROUTES.TEAMS }, + { name: "Teams", href: ROUTES.TEAMS, pulse: hasPendingInvites }, { name: "Zapier", href: ROUTES.ZAPIER }, { name: "Billing", href: ROUTES.BILLING }, { name: "Support", href: ROUTES.SUPPORT, external: true }, @@ -136,6 +150,9 @@ export default function HeaderComponent() { rel={item.external ? "noopener noreferrer" : null} > {item.name} + {item.pulse ? ( + + ) : null} ))} @@ -246,8 +263,9 @@ export default function HeaderComponent() {
{navigation.map((item) => ( - {item.name} - + {item.pulse ? ( + + ) : null} + ))} {!user && ( From af497df11e91cd8d94d527a100e1bed96822b26d Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Tue, 18 Feb 2025 18:13:50 +1100 Subject: [PATCH 2/3] Auto update header --- .../components/layout/header.component.tsx | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/apps/web/components/layout/header.component.tsx b/apps/web/components/layout/header.component.tsx index 906d7d0..d602cc4 100644 --- a/apps/web/components/layout/header.component.tsx +++ b/apps/web/components/layout/header.component.tsx @@ -34,6 +34,31 @@ export default function HeaderComponent() { .then(({ data }) => { setHasPendingInvites(data?.length > 0); }); + + const channel = supabase + .channel("schema-db-changes") + .on( + "postgres_changes", + { + event: "*", + schema: "public", + table: "team_invitations", + filter: `email=eq.${user.email}`, + }, + (payload) => { + const { new: newData, old: oldData } = payload; + if (newData) { + setHasPendingInvites(true); + } else if (oldData) { + setHasPendingInvites(false); + } + } + ) + .subscribe(); + + return () => { + channel.unsubscribe(); + }; }, [user]); const navigation = useMemo(() => { From 51372c5cf3c527290904ae1c91b128339c7d9aba Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Tue, 18 Feb 2025 18:26:57 +1100 Subject: [PATCH 3/3] Update migration --- packages/supabase/migrations/16_teams.sql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/supabase/migrations/16_teams.sql b/packages/supabase/migrations/16_teams.sql index 6fa815d..8def046 100644 --- a/packages/supabase/migrations/16_teams.sql +++ b/packages/supabase/migrations/16_teams.sql @@ -110,4 +110,6 @@ create table page_audit_logs ( ); alter table page_audit_logs enable row level security; -create policy "Can insert page audit logs." on page_audit_logs for insert with check (actor_id = auth.uid()); \ No newline at end of file +create policy "Can insert page audit logs." on page_audit_logs for insert with check (actor_id = auth.uid()); + +alter publication supabase_realtime add table team_invitations; \ No newline at end of file