From 45370f46c6ff1875c41f6b9b34e38045b856bf50 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Mon, 16 Jan 2023 18:36:25 +0800 Subject: [PATCH 01/18] Start to add createdAt and subscriptionCount to newsletter emails --- .../queries/useGetNewsletterEmailsQuery.tsx | 11 +- packages/web/pages/settings/emails.tsx | 418 +++++++++--------- 2 files changed, 215 insertions(+), 214 deletions(-) diff --git a/packages/web/lib/networking/queries/useGetNewsletterEmailsQuery.tsx b/packages/web/lib/networking/queries/useGetNewsletterEmailsQuery.tsx index ece0316be..92228a004 100644 --- a/packages/web/lib/networking/queries/useGetNewsletterEmailsQuery.tsx +++ b/packages/web/lib/networking/queries/useGetNewsletterEmailsQuery.tsx @@ -19,6 +19,8 @@ type NewsletterEmailsData = { export type NewsletterEmail = { id: string address: string + createdAt: Date + subscriptionCount: number confirmationCode?: string } @@ -30,6 +32,8 @@ export function useGetNewsletterEmailsQuery(): NewsletterEmailsQueryResponse { newsletterEmails { id address + createdAt + subscriptionCount confirmationCode } } @@ -46,13 +50,14 @@ export function useGetNewsletterEmailsQuery(): NewsletterEmailsQueryResponse { try { if (data) { const result = data as NewsletterEmailsResponseData - const emailAddresses = result.newsletterEmails?.newsletterEmails as NewsletterEmail[] + const emailAddresses = result.newsletterEmails + ?.newsletterEmails as NewsletterEmail[] return { isValidating, emailAddresses, revalidate: () => { mutate(undefined, true) - } + }, } } } catch (error) { @@ -62,6 +67,6 @@ export function useGetNewsletterEmailsQuery(): NewsletterEmailsQueryResponse { isValidating: false, emailAddresses: [], // eslint-disable-next-line @typescript-eslint/no-empty-function - revalidate: () => {} + revalidate: () => {}, } } diff --git a/packages/web/pages/settings/emails.tsx b/packages/web/pages/settings/emails.tsx index ce3bc53a4..d4e0aad1b 100644 --- a/packages/web/pages/settings/emails.tsx +++ b/packages/web/pages/settings/emails.tsx @@ -4,12 +4,11 @@ import { useGetNewsletterEmailsQuery } from '../../lib/networking/queries/useGet import { createNewsletterEmailMutation } from '../../lib/networking/mutations/createNewsletterEmailMutation' import { deleteNewsletterEmailMutation } from '../../lib/networking/mutations/deleteNewsletterEmailMutation' import { MoreOptionsIcon } from '../../components/elements/images/MoreOptionsIcon' -import { Info, Plus, Trash, Copy } from 'phosphor-react' +import { Plus, Trash, Copy } from 'phosphor-react' import { Dropdown, DropdownOption, } from '../../components/elements/DropdownElements' -import { TooltipWrapped } from '../../components/elements/Tooltip' import { theme, styled } from '../../components/tokens/stitches.config' import { Box, @@ -23,7 +22,6 @@ import { useCallback } from 'react' import { StyledText } from '../../components/elements/StyledText' import { applyStoredTheme } from '../../lib/themeUpdater' import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' -import Link from 'next/link' import { InfoLink } from '../../components/elements/InfoLink' enum TextType { @@ -69,7 +67,7 @@ const TableHeading = styled(Box, { width: '100%', '@md': { display: 'flex', - } + }, }) const Input = styled('input', { @@ -83,23 +81,19 @@ const Input = styled('input', { }) const CopyTextBtnWrapper = styled(Box, { - padding: '1px', background: '$grayBgActive', borderRadius: '6px', border: '1px solid rgba(0, 0, 0, 0.06)', -}) + width: '32px', + height: '32px', -const InfoIcon = styled(Info, { - marginTop: '8px', - '&:hover': { - cursor: 'pointer', - }, -}) + display: 'flex', -const TooltipStyle = { - backgroundColor: '#F9D354', - color: '#0A0806', -} + color: '#3D3D3D', + + alignItems: 'center', + justifyContent: 'center', +}) const MoreOptions = ({ onDelete }: { onDelete: () => void }) => ( { copyLink() - showSuccessToast(props.type == TextType.EmailAddress ? 'Email Address Copied' : 'Confirmation Code Copied'); + showSuccessToast( + props.type == TextType.EmailAddress + ? 'Email Address Copied' + : 'Confirmation Code Copied' + ) }, []) return ( ) } @@ -200,220 +202,214 @@ export default function EmailsPage(): JSX.Element { top: '5rem', }} /> - + - - - - - Email Addresses{' '} - - - - - - - - - EMAIL - - - - - CONFIRMATION CODE - - - - - {emailAddresses && - emailAddresses.map((email, i) => { - const { address, confirmationCode, id } = email - const isLastChild = i === emailAddresses.length - 1 - - return ( - - - Create a new email address + + + + + + + + + + Address + + + + + Created At + + + + + {emailAddresses && + emailAddresses.map((email, i) => { + const isLastChild = i === emailAddresses.length - 1 + + return ( + + - - - - - - deleteEmail(id)} /> - - - {confirmationCode && ( + + + {email.createdAt} + count: {email.subscriptionCount} + + + + + + deleteEmail(email.id)} /> + + + {email.confirmationCode && ( + + <> + + + + + + + + + )} + + + - <> - - - - - - - - - )} - - - - deleteEmail(id)} /> - - - - ) - })} - + deleteEmail(email.id)} /> + + + + ) + })} + + ) From cd0640493e5e6d242f4d3de0c2d11ccf30a2474b Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Mon, 16 Jan 2023 21:10:05 +0800 Subject: [PATCH 02/18] Display date created and number of subscriptions --- packages/web/lib/dateFormatting.ts | 6 ++ .../queries/useGetNewsletterEmailsQuery.tsx | 2 +- packages/web/pages/settings/emails.tsx | 63 +++++++++---------- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/packages/web/lib/dateFormatting.ts b/packages/web/lib/dateFormatting.ts index 3326a26e8..a987c7543 100644 --- a/packages/web/lib/dateFormatting.ts +++ b/packages/web/lib/dateFormatting.ts @@ -8,6 +8,12 @@ export function formattedLongDate(rawDate: string): string { }).format(new Date(rawDate)) } +export function formattedShortDate(rawDate: string): string { + return new Intl.DateTimeFormat(locale, { + dateStyle: 'short', + }).format(new Date(rawDate)) +} + export function readableUpdatedAtMessage( rawDate: string, customPrefix?: string diff --git a/packages/web/lib/networking/queries/useGetNewsletterEmailsQuery.tsx b/packages/web/lib/networking/queries/useGetNewsletterEmailsQuery.tsx index 92228a004..2020c21ab 100644 --- a/packages/web/lib/networking/queries/useGetNewsletterEmailsQuery.tsx +++ b/packages/web/lib/networking/queries/useGetNewsletterEmailsQuery.tsx @@ -19,7 +19,7 @@ type NewsletterEmailsData = { export type NewsletterEmail = { id: string address: string - createdAt: Date + createdAt: string subscriptionCount: number confirmationCode?: string } diff --git a/packages/web/pages/settings/emails.tsx b/packages/web/pages/settings/emails.tsx index d4e0aad1b..ad4e40f1a 100644 --- a/packages/web/pages/settings/emails.tsx +++ b/packages/web/pages/settings/emails.tsx @@ -23,6 +23,7 @@ import { StyledText } from '../../components/elements/StyledText' import { applyStoredTheme } from '../../lib/themeUpdater' import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' import { InfoLink } from '../../components/elements/InfoLink' +import { formattedShortDate } from '../../lib/dateFormatting' enum TextType { EmailAddress, @@ -62,7 +63,7 @@ const TableHeading = styled(Box, { border: '1px solid rgba(0, 0, 0, 0.06)', display: 'none', alignItems: 'center', - padding: '14px 0 14px 40px', + padding: '10px 0 10px 20px', borderRadius: '5px 5px 0px 0px', width: '100%', '@md': { @@ -93,6 +94,7 @@ const CopyTextBtnWrapper = styled(Box, { alignItems: 'center', justifyContent: 'center', + marginLeft: '10px', }) const MoreOptions = ({ onDelete }: { onDelete: () => void }) => ( @@ -260,30 +262,14 @@ export default function EmailsPage(): JSX.Element { - - - Address - - - - - Created At - - + Address + {emailAddresses && @@ -310,6 +296,7 @@ export default function EmailsPage(): JSX.Element { display: 'flex', width: '100%', flexDirection: 'column', + paddingLeft: '20px', '@md': { flexDirection: 'row', }, @@ -322,23 +309,29 @@ export default function EmailsPage(): JSX.Element { padding: '4px 4px 4px 0px', }} > - - + - {email.createdAt} - count: {email.subscriptionCount} + > + {email.address} + + + {`created ${formattedShortDate(email.createdAt)}, ${ + email.subscriptionCount + } subscriptions`} + Date: Mon, 16 Jan 2023 21:57:34 +0800 Subject: [PATCH 03/18] Style tweaks for the emails list --- packages/web/components/elements/InfoLink.tsx | 15 +++-- packages/web/pages/settings/emails.tsx | 66 +++++++++++-------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/packages/web/components/elements/InfoLink.tsx b/packages/web/components/elements/InfoLink.tsx index 0424f0b2e..ba9e50355 100644 --- a/packages/web/components/elements/InfoLink.tsx +++ b/packages/web/components/elements/InfoLink.tsx @@ -1,6 +1,6 @@ import Link from 'next/link' import { Info } from 'phosphor-react' -import { Box } from '../elements/LayoutPrimitives' +import { Box, VStack } from '../elements/LayoutPrimitives' import { theme } from '../tokens/stitches.config' import { TooltipWrapped } from './Tooltip' @@ -15,8 +15,14 @@ const TooltipStyle = { export function InfoLink(props: InfoLinkProps): JSX.Element { return ( - - + - - + ) } diff --git a/packages/web/pages/settings/emails.tsx b/packages/web/pages/settings/emails.tsx index ad4e40f1a..29fa58c85 100644 --- a/packages/web/pages/settings/emails.tsx +++ b/packages/web/pages/settings/emails.tsx @@ -18,7 +18,7 @@ import { } from '../../components/elements/LayoutPrimitives' import { useCopyLink } from '../../lib/hooks/useCopyLink' import { Toaster } from 'react-hot-toast' -import { useCallback } from 'react' +import { useCallback, useMemo } from 'react' import { StyledText } from '../../components/elements/StyledText' import { applyStoredTheme } from '../../lib/themeUpdater' import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' @@ -71,16 +71,6 @@ const TableHeading = styled(Box, { }, }) -const Input = styled('input', { - backgroundColor: 'transparent', - color: '$grayTextContrast', - marginTop: '5px', - marginLeft: '38px', - '&[disabled]': { - border: 'none', - }, -}) - const CopyTextBtnWrapper = styled(Box, { background: '$grayBgActive', borderRadius: '6px', @@ -197,6 +187,16 @@ export default function EmailsPage(): JSX.Element { revalidate() showSuccessToast('Email Deleted') } + + const sortedEmailAddresses = useMemo(() => { + return emailAddresses + .sort((a, b) => a.createdAt.localeCompare(b.createdAt)) + .map((em) => { + em.confirmationCode = '123445' + return em + }) + }, [emailAddresses]) + return ( - {emailAddresses && - emailAddresses.map((email, i) => { - const isLastChild = i === emailAddresses.length - 1 + {sortedEmailAddresses && + sortedEmailAddresses.map((email, i) => { + const isLastChild = i === sortedEmailAddresses.length - 1 return ( - + {email.confirmationCode && ( <> - + + {`Gmail: ${email.confirmationCode}`} + )} - + Date: Tue, 17 Jan 2023 15:28:35 +0800 Subject: [PATCH 04/18] Use same table base for emails and subscriptions --- .../templates/settings/SettingsTable.tsx | 309 +++++++++++++++ packages/web/pages/settings/emails.tsx | 374 ++++-------------- packages/web/pages/settings/subscriptions.tsx | 133 +++++-- 3 files changed, 479 insertions(+), 337 deletions(-) create mode 100644 packages/web/components/templates/settings/SettingsTable.tsx diff --git a/packages/web/components/templates/settings/SettingsTable.tsx b/packages/web/components/templates/settings/SettingsTable.tsx new file mode 100644 index 000000000..444d91086 --- /dev/null +++ b/packages/web/components/templates/settings/SettingsTable.tsx @@ -0,0 +1,309 @@ +import { Plus, Trash } from 'phosphor-react' +import { Toaster } from 'react-hot-toast' +import { Button } from '../../elements/Button' +import { Dropdown, DropdownOption } from '../../elements/DropdownElements' +import { MoreOptionsIcon } from '../../elements/images/MoreOptionsIcon' +import { InfoLink } from '../../elements/InfoLink' +import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives' +import { StyledText } from '../../elements/StyledText' +import { styled, theme } from '../../tokens/stitches.config' +import { PrimaryLayout } from '../PrimaryLayout' + +type SettingsTableProps = { + pageId: string + pageHeadline: string + pageInfoLink: string + headerTitle: string + + createTitle?: string + createAction?: () => void + + children: React.ReactNode +} + +type CreateButtonProps = { + title: string + action: () => void +} + +type SettingsTableRowProps = { + key: string + title: string + isFirst: boolean + isLast: boolean + + sublineElement: JSX.Element + titleElement?: JSX.Element + extraElement?: JSX.Element + + deleteTitle: string + onDelete: () => void +} + +type MoreOptionsProps = { + title: string + onDelete: () => void +} + +const MoreOptions = (props: MoreOptionsProps) => ( + + + + } + > + { + return true + }} + > + + + + + + +) + +export const SettingsTableRow = (props: SettingsTableRowProps): JSX.Element => { + return ( + + + + + + {props.title} + + {props.sublineElement} + + {props.titleElement} + {/* + + */} + + + + + {props.extraElement} + + + + + + + + ) +} + +const CreateButton = (props: CreateButtonProps): JSX.Element => { + return ( + + ) +} + +export const SettingsTable = (props: SettingsTableProps): JSX.Element => { + return ( + + + + + + + + + {props.pageHeadline}{' '} + + + + {props.createAction && props.createTitle && ( + + )} + + + + {props.headerTitle} + + + + {props.children} + + + + + ) +} diff --git a/packages/web/pages/settings/emails.tsx b/packages/web/pages/settings/emails.tsx index 29fa58c85..c7d16b1f3 100644 --- a/packages/web/pages/settings/emails.tsx +++ b/packages/web/pages/settings/emails.tsx @@ -1,29 +1,26 @@ -import { PrimaryLayout } from '../../components/templates/PrimaryLayout' import { Button } from '../../components/elements/Button' import { useGetNewsletterEmailsQuery } from '../../lib/networking/queries/useGetNewsletterEmailsQuery' import { createNewsletterEmailMutation } from '../../lib/networking/mutations/createNewsletterEmailMutation' import { deleteNewsletterEmailMutation } from '../../lib/networking/mutations/deleteNewsletterEmailMutation' import { MoreOptionsIcon } from '../../components/elements/images/MoreOptionsIcon' -import { Plus, Trash, Copy } from 'phosphor-react' +import { Trash, Copy } from 'phosphor-react' import { Dropdown, DropdownOption, } from '../../components/elements/DropdownElements' import { theme, styled } from '../../components/tokens/stitches.config' -import { - Box, - SpanBox, - HStack, - VStack, -} from '../../components/elements/LayoutPrimitives' +import { Box, HStack } from '../../components/elements/LayoutPrimitives' import { useCopyLink } from '../../lib/hooks/useCopyLink' -import { Toaster } from 'react-hot-toast' import { useCallback, useMemo } from 'react' import { StyledText } from '../../components/elements/StyledText' import { applyStoredTheme } from '../../lib/themeUpdater' import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' -import { InfoLink } from '../../components/elements/InfoLink' import { formattedShortDate } from '../../lib/dateFormatting' +import Link from 'next/link' +import { + SettingsTable, + SettingsTableRow, +} from '../../components/templates/settings/SettingsTable' enum TextType { EmailAddress, @@ -35,42 +32,6 @@ type CopyTextButtonProps = { type: TextType } -const HeaderWrapper = styled(Box, { - width: '100%', - '@md': { - display: 'block', - }, -}) - -const TableCard = styled(Box, { - backgroundColor: '$grayBg', - display: 'flex', - alignItems: 'center', - padding: '10px 12px', - border: '0.5px solid $grayBgActive', - width: '100%', - - '&:hover': { - border: '0.5px solid #FFD234', - }, - '@md': { - paddingLeft: '0', - }, -}) - -const TableHeading = styled(Box, { - backgroundColor: '$grayBgActive', - border: '1px solid rgba(0, 0, 0, 0.06)', - display: 'none', - alignItems: 'center', - padding: '10px 0 10px 20px', - borderRadius: '5px 5px 0px 0px', - width: '100%', - '@md': { - display: 'flex', - }, -}) - const CopyTextBtnWrapper = styled(Box, { background: '$grayBgActive', borderRadius: '6px', @@ -87,52 +48,6 @@ const CopyTextBtnWrapper = styled(Box, { marginLeft: '10px', }) -const MoreOptions = ({ onDelete }: { onDelete: () => void }) => ( - - - - } - > - { - return true - }} - > - - - - - - -) - function CopyTextButton(props: CopyTextButtonProps): JSX.Element { const { copyLink, isLinkCopied } = useCopyLink( props.text, @@ -198,224 +113,89 @@ export default function EmailsPage(): JSX.Element { }, [emailAddresses]) return ( - - - - - - - - Email Addresses - - - - - - - Address - - - - {sortedEmailAddresses && - sortedEmailAddresses.map((email, i) => { - const isLastChild = i === sortedEmailAddresses.length - 1 - - return ( - - - + + } + extraElement={ + + <> + - - - {email.address} - - - {`created ${formattedShortDate(email.createdAt)}, ${ - email.subscriptionCount - } subscriptions`} - - - - - - - deleteEmail(email.id)} /> - - - {email.confirmationCode && ( - - <> - - {`Gmail: ${email.confirmationCode}`} - - - - - - - - - )} - - - - deleteEmail(email.id)} /> + {`Gmail: ${email.confirmationCode}`} + + + + + - - - ) - })} - - - - + + + } + /> + ) + })} + ) } diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index 704edb121..473df7bb6 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -1,18 +1,20 @@ import { useState } from 'react' -import { PrimaryLayout } from '../../components/templates/PrimaryLayout' -import { Toaster } from 'react-hot-toast' import { applyStoredTheme } from '../../lib/themeUpdater' import { ConfirmationModal } from '../../components/patterns/ConfirmationModal' import { useGetSubscriptionsQuery } from '../../lib/networking/queries/useGetSubscriptionsQuery' import { unsubscribeMutation } from '../../lib/networking/mutations/unsubscribeMutation' import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' -import { Table } from '../../components/elements/Table' +import { + SettingsTable, + SettingsTableRow, +} from '../../components/templates/settings/SettingsTable' +import { StyledText } from '../../components/elements/StyledText' +import Link from 'next/link' export default function SubscriptionsPage(): JSX.Element { const { subscriptions, revalidate } = useGetSubscriptionsQuery() - const [confirmUnsubscribeName, setConfirmUnsubscribeName] = useState< - string | null - >(null) + const [confirmUnsubscribeName, setConfirmUnsubscribeName] = + useState(null) applyStoredTheme(false) @@ -26,42 +28,93 @@ export default function SubscriptionsPage(): JSX.Element { revalidate() } - const headers = ['Name', 'Email', 'Updated Time'] - const rows = new Map() - subscriptions.forEach((subscription) => - rows.set(subscription.name, [ - subscription.name, - subscription.newsletterEmail, - subscription.updatedAt.toString(), - ]) - ) + function formattedShortDate(date: Date): string { + return new Intl.DateTimeFormat('en-US', { + dateStyle: 'short', + }).format(date) + } return ( - - + + <> + {subscriptions && + subscriptions.map((subscription, i) => { + return ( + onUnsubscribe(subscription.name)} + deleteTitle="Unsubscribe" + sublineElement={ + + {`Last received ${formattedShortDate( + subscription.updatedAt + )}, `} + + {subscription.newsletterEmail} + + + } + /> + ) + })} - {confirmUnsubscribeName ? ( - { - await onUnsubscribe(confirmUnsubscribeName) - setConfirmUnsubscribeName(null) - }} - onOpenChange={() => setConfirmUnsubscribeName(null)} - /> - ) : null} - - + {confirmUnsubscribeName ? ( + { + await onUnsubscribe(confirmUnsubscribeName) + setConfirmUnsubscribeName(null) + }} + onOpenChange={() => setConfirmUnsubscribeName(null)} + /> + ) : null} + + ) + + // return ( + // + // + + // {confirmUnsubscribeName ? ( + // { + // await onUnsubscribe(confirmUnsubscribeName) + // setConfirmUnsubscribeName(null) + // }} + // onOpenChange={() => setConfirmUnsubscribeName(null)} + // /> + // ) : null} + //
+ // + // ) } From 844ac6ef129e4b8fa7ed20294a859e88979b1219 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 15:37:09 +0800 Subject: [PATCH 05/18] Dates are stored as strings in the API response --- .../lib/networking/queries/useGetSubscriptionsQuery.tsx | 4 ++-- packages/web/pages/settings/subscriptions.tsx | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx b/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx index 92ec8241a..526869c77 100644 --- a/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx +++ b/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx @@ -13,8 +13,8 @@ export type Subscription = { description?: string status: SubscriptionStatus - createdAt: Date - updatedAt: Date + createdAt: string + updatedAt: string } type SubscriptionsQueryResponse = { diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index 473df7bb6..46d91b383 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -10,6 +10,7 @@ import { } from '../../components/templates/settings/SettingsTable' import { StyledText } from '../../components/elements/StyledText' import Link from 'next/link' +import { formattedShortDate } from '../../lib/dateFormatting' export default function SubscriptionsPage(): JSX.Element { const { subscriptions, revalidate } = useGetSubscriptionsQuery() @@ -28,12 +29,6 @@ export default function SubscriptionsPage(): JSX.Element { revalidate() } - function formattedShortDate(date: Date): string { - return new Intl.DateTimeFormat('en-US', { - dateStyle: 'short', - }).format(date) - } - return ( Date: Tue, 17 Jan 2023 16:17:56 +0800 Subject: [PATCH 06/18] Improve text for subscription emails --- packages/web/pages/settings/subscriptions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index 46d91b383..7f45c1b16 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -56,7 +56,7 @@ export default function SubscriptionsPage(): JSX.Element { > {`Last received ${formattedShortDate( subscription.updatedAt - )}, `} + )} at `} From e9981b0fd65466877867ef0f6e895cdc82d0c812 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 16:18:09 +0800 Subject: [PATCH 07/18] Use resolved locale for date formatting --- packages/web/lib/dateFormatting.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/lib/dateFormatting.ts b/packages/web/lib/dateFormatting.ts index a987c7543..93be4d330 100644 --- a/packages/web/lib/dateFormatting.ts +++ b/packages/web/lib/dateFormatting.ts @@ -1,6 +1,6 @@ //https://github.com/you-dont-need/You-Dont-Need-Momentjs -const locale = 'en-US' //navigator?.language ?? 'en-US' +const locale = Intl.DateTimeFormat().resolvedOptions().locale || 'en-US' export function formattedLongDate(rawDate: string): string { return new Intl.DateTimeFormat(locale, { From 30155f1321efb09854d3022804253d4132de2460 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 17:45:21 +0800 Subject: [PATCH 08/18] Empty rows for table settings, formatting fixes, less differences between mobile web and desktop --- packages/web/components/elements/InfoLink.tsx | 5 +- .../templates/settings/SettingsTable.tsx | 104 +++++++++--------- packages/web/pages/settings/emails.tsx | 14 ++- packages/web/pages/settings/subscriptions.tsx | 10 +- 4 files changed, 67 insertions(+), 66 deletions(-) diff --git a/packages/web/components/elements/InfoLink.tsx b/packages/web/components/elements/InfoLink.tsx index ba9e50355..c250ca7e9 100644 --- a/packages/web/components/elements/InfoLink.tsx +++ b/packages/web/components/elements/InfoLink.tsx @@ -18,12 +18,9 @@ export function InfoLink(props: InfoLinkProps): JSX.Element { - + ( ) +type EmptySettingsRowProps = { + text: string +} + +export const EmptySettingsRow = (props: EmptySettingsRowProps): JSX.Element => { + return ( + + {props.text} + + ) +} + export const SettingsTableRow = (props: SettingsTableRowProps): JSX.Element => { return ( { '&:hover': { background: 'rgba(255, 234, 159, 0.12)', }, - '@mdDown': { - borderTopLeftRadius: props.isFirst ? '5px' : '', - borderTopRightRadius: props.isFirst ? '5px' : '', - }, borderBottomLeftRadius: props.isLast ? '5px' : '', borderBottomRightRadius: props.isLast ? '5px' : '', '@md': { @@ -134,7 +157,7 @@ export const SettingsTableRow = (props: SettingsTableRowProps): JSX.Element => { padding: '4px 4px 4px 0px', }} > - + { {props.sublineElement} {props.titleElement} - {/* - - */} { marginLeft: 'auto', }} > - - {props.title} - - - - + {props.title} ) } @@ -262,13 +256,13 @@ export const SettingsTable = (props: SettingsTableProps): JSX.Element => { }, }} > - - - - {props.pageHeadline}{' '} - - - + {props.createAction && props.createTitle && ( { css={{ backgroundColor: '$grayBgActive', border: '1px solid rgba(0, 0, 0, 0.06)', - display: 'none', + borderBottom: 'unset', alignItems: 'center', padding: '10px 0 10px 20px', borderRadius: '5px 5px 0px 0px', width: '100%', - '@md': { - display: 'flex', - }, }} > - - {props.headerTitle} - + + + {props.headerTitle} + + + {props.children} diff --git a/packages/web/pages/settings/emails.tsx b/packages/web/pages/settings/emails.tsx index c7d16b1f3..fa49605ea 100644 --- a/packages/web/pages/settings/emails.tsx +++ b/packages/web/pages/settings/emails.tsx @@ -18,6 +18,7 @@ import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' import { formattedShortDate } from '../../lib/dateFormatting' import Link from 'next/link' import { + EmptySettingsRow, SettingsTable, SettingsTableRow, } from '../../components/templates/settings/SettingsTable' @@ -45,7 +46,6 @@ const CopyTextBtnWrapper = styled(Box, { alignItems: 'center', justifyContent: 'center', - marginLeft: '10px', }) function CopyTextButton(props: CopyTextButtonProps): JSX.Element { @@ -121,13 +121,12 @@ export default function EmailsPage(): JSX.Element { createTitle="Create a new email address" createAction={createEmail} > - {sortedEmailAddresses && + {sortedEmailAddresses ? ( sortedEmailAddresses.map((email, i) => { return ( deleteEmail(email.id)} deleteTitle="Delete" @@ -178,6 +177,10 @@ export default function EmailsPage(): JSX.Element { '@md': { marginTop: '5px', }, + '@mdDown': { + marginLeft: 'auto', + }, + marginRight: '10px', }} > {`Gmail: ${email.confirmationCode}`} @@ -195,7 +198,10 @@ export default function EmailsPage(): JSX.Element { } /> ) - })} + }) + ) : ( + + )} ) } diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index 7f45c1b16..0a4c256e1 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -5,12 +5,14 @@ import { useGetSubscriptionsQuery } from '../../lib/networking/queries/useGetSub import { unsubscribeMutation } from '../../lib/networking/mutations/unsubscribeMutation' import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' import { + EmptySettingsRow, SettingsTable, SettingsTableRow, } from '../../components/templates/settings/SettingsTable' import { StyledText } from '../../components/elements/StyledText' import Link from 'next/link' import { formattedShortDate } from '../../lib/dateFormatting' +import { Box } from '../../components/elements/LayoutPrimitives' export default function SubscriptionsPage(): JSX.Element { const { subscriptions, revalidate } = useGetSubscriptionsQuery() @@ -37,13 +39,12 @@ export default function SubscriptionsPage(): JSX.Element { headerTitle="Subscriptions" > <> - {subscriptions && + {subscriptions.length > 0 ? ( subscriptions.map((subscription, i) => { return ( onUnsubscribe(subscription.name)} deleteTitle="Unsubscribe" @@ -66,7 +67,10 @@ export default function SubscriptionsPage(): JSX.Element { } /> ) - })} + }) + ) : ( + + )} {confirmUnsubscribeName ? ( Date: Tue, 17 Jan 2023 17:54:02 +0800 Subject: [PATCH 09/18] Remove stubbed confirmation codes --- packages/web/pages/settings/emails.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/web/pages/settings/emails.tsx b/packages/web/pages/settings/emails.tsx index fa49605ea..8ba8d1efd 100644 --- a/packages/web/pages/settings/emails.tsx +++ b/packages/web/pages/settings/emails.tsx @@ -104,12 +104,7 @@ export default function EmailsPage(): JSX.Element { } const sortedEmailAddresses = useMemo(() => { - return emailAddresses - .sort((a, b) => a.createdAt.localeCompare(b.createdAt)) - .map((em) => { - em.confirmationCode = '123445' - return em - }) + return emailAddresses.sort((a, b) => a.createdAt.localeCompare(b.createdAt)) }, [emailAddresses]) return ( From 60c77bb5f835e5389df98317cada002b705f2970 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 18:06:46 +0800 Subject: [PATCH 10/18] Dont show empty row state when loading data --- packages/web/pages/settings/emails.tsx | 4 +++- packages/web/pages/settings/subscriptions.tsx | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/web/pages/settings/emails.tsx b/packages/web/pages/settings/emails.tsx index 8ba8d1efd..cef66c354 100644 --- a/packages/web/pages/settings/emails.tsx +++ b/packages/web/pages/settings/emails.tsx @@ -195,7 +195,9 @@ export default function EmailsPage(): JSX.Element { ) }) ) : ( - + )} ) diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index 0a4c256e1..577e3c709 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -15,7 +15,7 @@ import { formattedShortDate } from '../../lib/dateFormatting' import { Box } from '../../components/elements/LayoutPrimitives' export default function SubscriptionsPage(): JSX.Element { - const { subscriptions, revalidate } = useGetSubscriptionsQuery() + const { subscriptions, revalidate, isValidating } = useGetSubscriptionsQuery() const [confirmUnsubscribeName, setConfirmUnsubscribeName] = useState(null) @@ -69,7 +69,9 @@ export default function SubscriptionsPage(): JSX.Element { ) }) ) : ( - + )} {confirmUnsubscribeName ? ( From 60db01a308a463ac58df9faf3c0264433ced770f Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 18:22:26 +0800 Subject: [PATCH 11/18] Remove unused import --- packages/web/pages/settings/subscriptions.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index 577e3c709..7ae2188c2 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -12,7 +12,6 @@ import { import { StyledText } from '../../components/elements/StyledText' import Link from 'next/link' import { formattedShortDate } from '../../lib/dateFormatting' -import { Box } from '../../components/elements/LayoutPrimitives' export default function SubscriptionsPage(): JSX.Element { const { subscriptions, revalidate, isValidating } = useGetSubscriptionsQuery() From 2999a7a66e501a9cddfeb8c6355a026fc4dbfe8f Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 18:26:09 +0800 Subject: [PATCH 12/18] Add some debugging --- packages/web/pages/settings/subscriptions.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index 7ae2188c2..9399dd00f 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -18,6 +18,14 @@ export default function SubscriptionsPage(): JSX.Element { const [confirmUnsubscribeName, setConfirmUnsubscribeName] = useState(null) + console.log( + 'subscriptions', + subscriptions, + subscriptions.length, + 'isValidating', + isValidating + ) + applyStoredTheme(false) async function onUnsubscribe(name: string): Promise { From 443b41660195ecb0e80b53cb98bedf252c02199b Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 18:46:39 +0800 Subject: [PATCH 13/18] Return true for isValidating if no data found --- .../lib/networking/queries/useGetSubscriptionsQuery.tsx | 3 +-- packages/web/pages/settings/subscriptions.tsx | 8 -------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx b/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx index 526869c77..bacb0e5bb 100644 --- a/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx +++ b/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx @@ -57,7 +57,6 @@ export function useGetSubscriptionsQuery(): SubscriptionsQueryResponse { ` const { data, mutate, error, isValidating } = useSWR(query, publicGqlFetcher) - console.log('subscriptions data', data) try { if (data) { @@ -75,7 +74,7 @@ export function useGetSubscriptionsQuery(): SubscriptionsQueryResponse { console.log('error', error) } return { - isValidating: false, + isValidating: true, subscriptions: [], // eslint-disable-next-line @typescript-eslint/no-empty-function revalidate: () => {}, diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index 9399dd00f..7ae2188c2 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -18,14 +18,6 @@ export default function SubscriptionsPage(): JSX.Element { const [confirmUnsubscribeName, setConfirmUnsubscribeName] = useState(null) - console.log( - 'subscriptions', - subscriptions, - subscriptions.length, - 'isValidating', - isValidating - ) - applyStoredTheme(false) async function onUnsubscribe(name: string): Promise { From 501d0c2d4d4db05165267ca58f3ca5e8a1cb35c5 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 18:59:33 +0800 Subject: [PATCH 14/18] Using dash indicates loading and takes up more space so the row doesnt resize --- packages/web/pages/settings/emails.tsx | 2 +- packages/web/pages/settings/subscriptions.tsx | 31 +------------------ 2 files changed, 2 insertions(+), 31 deletions(-) diff --git a/packages/web/pages/settings/emails.tsx b/packages/web/pages/settings/emails.tsx index cef66c354..e25705b2e 100644 --- a/packages/web/pages/settings/emails.tsx +++ b/packages/web/pages/settings/emails.tsx @@ -196,7 +196,7 @@ export default function EmailsPage(): JSX.Element { }) ) : ( )} diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index 7ae2188c2..f21fdaf59 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -69,7 +69,7 @@ export default function SubscriptionsPage(): JSX.Element { }) ) : ( )} @@ -88,33 +88,4 @@ export default function SubscriptionsPage(): JSX.Element { ) - - // return ( - // - // - - // {confirmUnsubscribeName ? ( - // { - // await onUnsubscribe(confirmUnsubscribeName) - // setConfirmUnsubscribeName(null) - // }} - // onOpenChange={() => setConfirmUnsubscribeName(null)} - // /> - // ) : null} - //
- // - // ) } From 4ca1269610f1bdbd35689b263ad77b6bb25199ab Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 19:39:24 +0800 Subject: [PATCH 15/18] Show confirmation when unsubscribing --- packages/web/pages/settings/subscriptions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index f21fdaf59..f01c2af56 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -45,7 +45,7 @@ export default function SubscriptionsPage(): JSX.Element { key={subscription.id} title={subscription.name} isLast={i === subscriptions.length - 1} - onDelete={() => onUnsubscribe(subscription.name)} + onDelete={() => setConfirmUnsubscribeName(subscription.name)} deleteTitle="Unsubscribe" sublineElement={ Date: Tue, 17 Jan 2023 20:11:54 +0800 Subject: [PATCH 16/18] Add confirmation for deleting emails --- .../templates/settings/SettingsTable.tsx | 5 +- packages/web/pages/settings/emails.tsx | 201 ++++++++++-------- 2 files changed, 116 insertions(+), 90 deletions(-) diff --git a/packages/web/components/templates/settings/SettingsTable.tsx b/packages/web/components/templates/settings/SettingsTable.tsx index 4a97edb59..293d2f38e 100644 --- a/packages/web/components/templates/settings/SettingsTable.tsx +++ b/packages/web/components/templates/settings/SettingsTable.tsx @@ -155,6 +155,9 @@ export const SettingsTableRow = (props: SettingsTableRowProps): JSX.Element => { css={{ display: 'flex', padding: '4px 4px 4px 0px', + '@md': { + width: '70%', + }, }} > @@ -172,7 +175,7 @@ export const SettingsTableRow = (props: SettingsTableRowProps): JSX.Element => { {props.sublineElement} - {props.titleElement} + {props.titleElement} (undefined) applyStoredTheme(false) @@ -108,97 +111,117 @@ export default function EmailsPage(): JSX.Element { }, [emailAddresses]) return ( - - {sortedEmailAddresses ? ( - sortedEmailAddresses.map((email, i) => { - return ( - deleteEmail(email.id)} - deleteTitle="Delete" - sublineElement={ - - {`created ${formattedShortDate(email.createdAt)}, `} - {`${email.subscriptionCount} subscriptions`} - - } - titleElement={ - - - - } - extraElement={ - - <> - + + {sortedEmailAddresses.length > 0 ? ( + sortedEmailAddresses.map((email, i) => { + return ( + setConfirmDeleteEmailId(email.id)} + deleteTitle="Delete" + sublineElement={ + + {`created ${formattedShortDate(email.createdAt)}, `} + {`${email.subscriptionCount} subscriptions`} + + } + titleElement={ + + + + } + extraElement={ + email.confirmationCode ? ( + - {`Gmail: ${email.confirmationCode}`} - - - - - - - - - } - /> - ) - }) - ) : ( - + + {`Gmail: ${email.confirmationCode}`} + + + + + + + + + ) : ( + <> + ) + } + /> + ) + }) + ) : ( + + )} + + + {confirmDeleteEmailId ? ( + { + await deleteEmail(confirmDeleteEmailId) + setConfirmDeleteEmailId(undefined) + }} + onOpenChange={() => setConfirmDeleteEmailId(undefined)} /> - )} - + ) : null} + ) } From 9fb5de24855e51b371db4ac59a42dde5f83f6bb4 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 20:27:06 +0800 Subject: [PATCH 17/18] Sort the subscriptions list --- packages/web/pages/settings/subscriptions.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index f01c2af56..9a0a5d8a9 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useMemo, useState } from 'react' import { applyStoredTheme } from '../../lib/themeUpdater' import { ConfirmationModal } from '../../components/patterns/ConfirmationModal' import { useGetSubscriptionsQuery } from '../../lib/networking/queries/useGetSubscriptionsQuery' @@ -30,6 +30,10 @@ export default function SubscriptionsPage(): JSX.Element { revalidate() } + const sortedSubscriptions = useMemo(() => { + return subscriptions.sort((a, b) => a.updatedAt.localeCompare(b.updatedAt)) + }, [subscriptions]) + return ( <> - {subscriptions.length > 0 ? ( - subscriptions.map((subscription, i) => { + {sortedSubscriptions.length > 0 ? ( + sortedSubscriptions.map((subscription, i) => { return ( setConfirmUnsubscribeName(subscription.name)} deleteTitle="Unsubscribe" sublineElement={ From 3d90eec421e5f7aed54c16185172016165da9183 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 20:42:55 +0800 Subject: [PATCH 18/18] Reverse sort order --- packages/web/pages/settings/subscriptions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx index 9a0a5d8a9..25212657a 100644 --- a/packages/web/pages/settings/subscriptions.tsx +++ b/packages/web/pages/settings/subscriptions.tsx @@ -31,7 +31,7 @@ export default function SubscriptionsPage(): JSX.Element { } const sortedSubscriptions = useMemo(() => { - return subscriptions.sort((a, b) => a.updatedAt.localeCompare(b.updatedAt)) + return subscriptions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)) }, [subscriptions]) return (