From 44be712fd64b2de68a426f9e5718d9188e1f7c84 Mon Sep 17 00:00:00 2001 From: Aryan Prince Date: Sun, 11 Aug 2024 23:26:49 +0100 Subject: [PATCH 1/6] fix: Add unsubscribe functionality to `NewsletterModal` (#209) - Pass the `mutate` prop from parent component to the `NewsletterModal` component - Uses the `useUnsubscribeButton` hook to manage the newsletter unsubscription - On clicking the unsubscribe button from the modal, calls the `onUnsubscribe` function from the `useUnsubscribeButton` hook Fixes #209 --- .../BulkUnsubscribeSection.tsx | 13 ++++--- apps/web/app/(app)/stats/NewsletterModal.tsx | 34 ++++++++++++++++--- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/apps/web/app/(app)/bulk-unsubscribe/BulkUnsubscribeSection.tsx b/apps/web/app/(app)/bulk-unsubscribe/BulkUnsubscribeSection.tsx index 31d5b29c2..aced0436c 100644 --- a/apps/web/app/(app)/bulk-unsubscribe/BulkUnsubscribeSection.tsx +++ b/apps/web/app/(app)/bulk-unsubscribe/BulkUnsubscribeSection.tsx @@ -223,11 +223,14 @@ export function BulkUnsubscribeSection(props: { )} - setOpenedNewsletter(undefined)} - refreshInterval={props.refreshInterval} - /> + {openedNewsletter && ( + setOpenedNewsletter(undefined)} + refreshInterval={props.refreshInterval} + mutate={mutate} + /> + )} ); diff --git a/apps/web/app/(app)/stats/NewsletterModal.tsx b/apps/web/app/(app)/stats/NewsletterModal.tsx index 0ff1fd5bb..8e9467e65 100644 --- a/apps/web/app/(app)/stats/NewsletterModal.tsx +++ b/apps/web/app/(app)/stats/NewsletterModal.tsx @@ -21,27 +21,46 @@ import { SectionHeader } from "@/components/Typography"; import { EmailList } from "@/components/email-list/EmailList"; import type { ThreadsResponse } from "@/app/api/google/threads/controller"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { Button } from "@/components/ui/button"; +import { Button, ButtonLoader } from "@/components/ui/button"; import { getGmailFilterSettingsUrl } from "@/utils/url"; import { Tooltip } from "@/components/Tooltip"; import { AlertBasic } from "@/components/Alert"; import { onAutoArchive } from "@/utils/actions/client"; -import { MoreDropdown } from "@/app/(app)/bulk-unsubscribe/common"; +import { + MoreDropdown, + useUnsubscribeButton, +} from "@/app/(app)/bulk-unsubscribe/common"; import { useLabels } from "@/hooks/useLabels"; import { Row } from "@/app/(app)/bulk-unsubscribe/types"; +import { usePremium } from "@/components/PremiumAlert"; +import { usePostHog } from "posthog-js/react"; export function NewsletterModal(props: { - newsletter?: Pick; + newsletter: Pick; onClose: (isOpen: boolean) => void; refreshInterval?: number; + mutate?: () => Promise; }) { const { newsletter, refreshInterval, onClose } = props; + const mutate = props.mutate || (() => Promise.resolve()); // Set a default value for mutate if it's not provided const session = useSession(); const email = session.data?.user.email; const { userLabels } = useLabels(); + const { hasUnsubscribeAccess, mutate: refetchPremium } = usePremium(); + + const posthog = usePostHog(); + + const { unsubscribeLoading, onUnsubscribe } = useUnsubscribeButton({ + item: newsletter, + hasUnsubscribeAccess, + mutate, + posthog, + refetchPremium, + }); + return ( @@ -57,8 +76,15 @@ export function NewsletterModal(props: { href={newsletter.lastUnsubscribeLink || undefined} target="_blank" rel="noreferrer" + onClick={onUnsubscribe} > - Unsubscribe + {!unsubscribeLoading && Unsubscribe} + {!!unsubscribeLoading && ( +
+ + Unsubscribing... +
+ )} From 2f53ad3fd661651f0e40be18493b39da6392642a Mon Sep 17 00:00:00 2001 From: Aryan Prince Date: Sun, 11 Aug 2024 23:29:40 +0100 Subject: [PATCH 2/6] refactor: Update `NewsletterModal` usages throughout app - Updates `NewsletterModal` component's usage throughout application as one of its props is no longer optional --- .../app/(app)/cold-email-blocker/ColdEmailList.tsx | 12 ++++++------ .../(app)/cold-email-blocker/ColdEmailRejected.tsx | 12 ++++++------ apps/web/app/(app)/new-senders/NewSenders.tsx | 12 +++++++----- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/apps/web/app/(app)/cold-email-blocker/ColdEmailList.tsx b/apps/web/app/(app)/cold-email-blocker/ColdEmailList.tsx index e77c783a9..d8c915fca 100644 --- a/apps/web/app/(app)/cold-email-blocker/ColdEmailList.tsx +++ b/apps/web/app/(app)/cold-email-blocker/ColdEmailList.tsx @@ -143,12 +143,12 @@ export function ColdEmailList() { - setOpenedRow(undefined)} - /> + {openedRow && ( + setOpenedRow(undefined)} + /> + )} ) : ( diff --git a/apps/web/app/(app)/cold-email-blocker/ColdEmailRejected.tsx b/apps/web/app/(app)/cold-email-blocker/ColdEmailRejected.tsx index 38341e661..92f7934ed 100644 --- a/apps/web/app/(app)/cold-email-blocker/ColdEmailRejected.tsx +++ b/apps/web/app/(app)/cold-email-blocker/ColdEmailRejected.tsx @@ -65,12 +65,12 @@ export function ColdEmailRejected() { - setOpenedRow(undefined)} - /> + {openedRow && ( + setOpenedRow(undefined)} + /> + )} ) : ( diff --git a/apps/web/app/(app)/new-senders/NewSenders.tsx b/apps/web/app/(app)/new-senders/NewSenders.tsx index 44c687126..aea6ed2c4 100644 --- a/apps/web/app/(app)/new-senders/NewSenders.tsx +++ b/apps/web/app/(app)/new-senders/NewSenders.tsx @@ -211,11 +211,13 @@ export function NewSenders(props: {
{extra}
- setOpenedNewsletter(undefined)} - refreshInterval={props.refreshInterval} - /> + {openedNewsletter && ( + setOpenedNewsletter(undefined)} + refreshInterval={props.refreshInterval} + /> + )} ); From 1b7c1b8fd160e8afd7db6fb9349396bb38bd780d Mon Sep 17 00:00:00 2001 From: Aryan Prince Date: Fri, 23 Aug 2024 12:05:29 +0100 Subject: [PATCH 3/6] refactor: Add button disabled state, use ternary logic instead Resolves a PR comment --- apps/web/app/(app)/stats/NewsletterModal.tsx | 55 +++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/apps/web/app/(app)/stats/NewsletterModal.tsx b/apps/web/app/(app)/stats/NewsletterModal.tsx index 8e9467e65..4128a622a 100644 --- a/apps/web/app/(app)/stats/NewsletterModal.tsx +++ b/apps/web/app/(app)/stats/NewsletterModal.tsx @@ -1,39 +1,39 @@ -import useSWR from "swr"; -import { BarChart } from "@tremor/react"; -import type { DateRange } from "react-day-picker"; -import Link from "next/link"; -import { ExternalLinkIcon } from "lucide-react"; -import { useSession } from "next-auth/react"; import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; + MoreDropdown, + useUnsubscribeButton, +} from "@/app/(app)/bulk-unsubscribe/common"; +import { Row } from "@/app/(app)/bulk-unsubscribe/types"; import { getDateRangeParams } from "@/app/(app)/stats/params"; +import type { ThreadsResponse } from "@/app/api/google/threads/controller"; import type { SenderEmailsQuery, SenderEmailsResponse, } from "@/app/api/user/stats/sender-emails/route"; -import type { ZodPeriod } from "@inboxzero/tinybird"; +import { AlertBasic } from "@/components/Alert"; import { LoadingContent } from "@/components/LoadingContent"; +import { usePremium } from "@/components/PremiumAlert"; +import { Tooltip } from "@/components/Tooltip"; import { SectionHeader } from "@/components/Typography"; import { EmailList } from "@/components/email-list/EmailList"; -import type { ThreadsResponse } from "@/app/api/google/threads/controller"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Button, ButtonLoader } from "@/components/ui/button"; -import { getGmailFilterSettingsUrl } from "@/utils/url"; -import { Tooltip } from "@/components/Tooltip"; -import { AlertBasic } from "@/components/Alert"; -import { onAutoArchive } from "@/utils/actions/client"; import { - MoreDropdown, - useUnsubscribeButton, -} from "@/app/(app)/bulk-unsubscribe/common"; + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { useLabels } from "@/hooks/useLabels"; -import { Row } from "@/app/(app)/bulk-unsubscribe/types"; -import { usePremium } from "@/components/PremiumAlert"; +import { onAutoArchive } from "@/utils/actions/client"; +import { getGmailFilterSettingsUrl } from "@/utils/url"; +import type { ZodPeriod } from "@inboxzero/tinybird"; +import { BarChart } from "@tremor/react"; +import { ExternalLinkIcon } from "lucide-react"; +import { useSession } from "next-auth/react"; +import Link from "next/link"; import { usePostHog } from "posthog-js/react"; +import type { DateRange } from "react-day-picker"; +import useSWR from "swr"; export function NewsletterModal(props: { newsletter: Pick; @@ -71,19 +71,22 @@ export function NewsletterModal(props: {
- From 6ff6a65ae607184ab49344fbfd9b9c81431bfe83 Mon Sep 17 00:00:00 2001 From: Aryan Prince Date: Tue, 24 Sep 2024 09:17:00 +0300 Subject: [PATCH 4/6] chore: Remove button loading state comments --- apps/web/app/(app)/stats/NewsletterModal.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/web/app/(app)/stats/NewsletterModal.tsx b/apps/web/app/(app)/stats/NewsletterModal.tsx index 4128a622a..feab0df47 100644 --- a/apps/web/app/(app)/stats/NewsletterModal.tsx +++ b/apps/web/app/(app)/stats/NewsletterModal.tsx @@ -79,13 +79,11 @@ export function NewsletterModal(props: { onClick={onUnsubscribe} > {unsubscribeLoading ? ( - // Button loading state
Unsubscribing...
) : ( - // Button default state Unsubscribe )} From ae22a6c1a9cffae3315f7395de9d83f199f500df Mon Sep 17 00:00:00 2001 From: Aryan Prince Date: Tue, 24 Sep 2024 12:27:30 +0300 Subject: [PATCH 5/6] fix: Add missing `mutate` prop to `NewsletterModal` --- apps/web/app/(app)/cold-email-blocker/ColdEmailList.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/app/(app)/cold-email-blocker/ColdEmailList.tsx b/apps/web/app/(app)/cold-email-blocker/ColdEmailList.tsx index 3e386f553..337fa297c 100644 --- a/apps/web/app/(app)/cold-email-blocker/ColdEmailList.tsx +++ b/apps/web/app/(app)/cold-email-blocker/ColdEmailList.tsx @@ -146,8 +146,9 @@ export function ColdEmailList() { {openedRow && ( setOpenedRow(undefined)} + mutate={mutate} /> )}
From 17ce178529586524d1567042ec63a376723b8df2 Mon Sep 17 00:00:00 2001 From: Aryan Prince Date: Tue, 24 Sep 2024 12:30:52 +0300 Subject: [PATCH 6/6] fix: `refreshInterval` now accessed directly, pass `mutate` prop --- apps/web/app/(app)/new-senders/NewSenders.tsx | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/apps/web/app/(app)/new-senders/NewSenders.tsx b/apps/web/app/(app)/new-senders/NewSenders.tsx index f24a4880c..7d69b577c 100644 --- a/apps/web/app/(app)/new-senders/NewSenders.tsx +++ b/apps/web/app/(app)/new-senders/NewSenders.tsx @@ -1,35 +1,25 @@ "use client"; -import React, { useState } from "react"; -import useSWR from "swr"; -import { useSession } from "next-auth/react"; -import { usePostHog } from "posthog-js/react"; -import { Card, Title } from "@tremor/react"; -import groupBy from "lodash/groupBy"; -import { FilterIcon, Users2Icon } from "lucide-react"; -import { LoadingContent } from "@/components/LoadingContent"; -import { Skeleton } from "@/components/ui/skeleton"; -import { useExpanded } from "@/app/(app)/stats/useExpanded"; -import { NewsletterModal } from "@/app/(app)/stats/NewsletterModal"; -import type { - NewSendersQuery, - NewSendersResponse, -} from "@/app/api/user/stats/new-senders/route"; -import { formatShortDate } from "@/utils/date"; -import { formatStat } from "@/utils/stats"; -import { StatsCards } from "@/components/StatsCards"; import { ActionCell, HeaderButton } from "@/app/(app)/bulk-unsubscribe/common"; import { - useNewsletterFilter, useBulkUnsubscribeShortcuts, + useNewsletterFilter, } from "@/app/(app)/bulk-unsubscribe/hooks"; +import { ShortcutTooltip } from "@/app/(app)/bulk-unsubscribe/ShortcutTooltip"; +import type { Row } from "@/app/(app)/bulk-unsubscribe/types"; +import { usePremiumModal } from "@/app/(app)/premium/PremiumModal"; import { DetailedStatsFilter } from "@/app/(app)/stats/DetailedStatsFilter"; +import { NewsletterModal } from "@/app/(app)/stats/NewsletterModal"; +import { useExpanded } from "@/app/(app)/stats/useExpanded"; import type { LabelsResponse } from "@/app/api/google/labels/route"; +import type { + NewSendersQuery, + NewSendersResponse, +} from "@/app/api/user/stats/new-senders/route"; +import { LoadingContent } from "@/components/LoadingContent"; import { usePremium } from "@/components/PremiumAlert"; -import { usePremiumModal } from "@/app/(app)/premium/PremiumModal"; -import { useLabels } from "@/hooks/useLabels"; -import { ShortcutTooltip } from "@/app/(app)/bulk-unsubscribe/ShortcutTooltip"; -import type { Row } from "@/app/(app)/bulk-unsubscribe/types"; +import { StatsCards } from "@/components/StatsCards"; +import { Skeleton } from "@/components/ui/skeleton"; import { Table, TableBody, @@ -38,6 +28,16 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; +import { useLabels } from "@/hooks/useLabels"; +import { formatShortDate } from "@/utils/date"; +import { formatStat } from "@/utils/stats"; +import { Card, Title } from "@tremor/react"; +import groupBy from "lodash/groupBy"; +import { FilterIcon, Users2Icon } from "lucide-react"; +import { useSession } from "next-auth/react"; +import { usePostHog } from "posthog-js/react"; +import React, { useState } from "react"; +import useSWR from "swr"; export function NewSenders({ refreshInterval }: { refreshInterval: number }) { const session = useSession(); @@ -215,7 +215,8 @@ export function NewSenders({ refreshInterval }: { refreshInterval: number }) { setOpenedNewsletter(undefined)} - refreshInterval={props.refreshInterval} + refreshInterval={refreshInterval} + mutate={mutate} /> )}