From 23b1f13522c7a74f25a4f2daee546b9c94cccc4a Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 17 Jan 2023 15:28:35 +0800 Subject: [PATCH] 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} + //
+ // + // ) }