diff --git a/packages/api/src/resolvers/subscriptions/index.ts b/packages/api/src/resolvers/subscriptions/index.ts
index 766eb6b0f..7936b25e5 100644
--- a/packages/api/src/resolvers/subscriptions/index.ts
+++ b/packages/api/src/resolvers/subscriptions/index.ts
@@ -37,25 +37,22 @@ export const subscriptionsResolver = authorized<
try {
const sortBy = sort?.by === SortBy.UpdatedTime ? 'updatedAt' : 'createdAt'
const sortOrder = sort?.order === SortOrder.Ascending ? 'ASC' : 'DESC'
- const user = await getRepository(User).findOne({
- where: { id: uid, subscriptions: { status: SubscriptionStatus.Active } },
- relations: {
- subscriptions: true,
- },
- order: {
- subscriptions: {
- [sortBy]: sortOrder,
- },
- },
- })
+ const user = await getRepository(User).findOneBy({ id: uid })
if (!user) {
return {
errorCodes: [SubscriptionsErrorCode.Unauthorized],
}
}
+ const subscriptions = await getRepository(Subscription).find({
+ where: { user: { id: uid }, status: SubscriptionStatus.Active },
+ order: {
+ [sortBy]: sortOrder,
+ },
+ })
+
return {
- subscriptions: user.subscriptions || [],
+ subscriptions,
}
} catch (error) {
log.error(error)
@@ -73,9 +70,12 @@ export const unsubscribeResolver = authorized<
log.info('unsubscribeResolver')
try {
- const subscription = await getRepository(Subscription).findOneBy({
- name,
- user: { id: uid },
+ const subscription = await getRepository(Subscription).findOne({
+ where: {
+ name,
+ user: { id: uid },
+ },
+ relations: ['user'],
})
if (!subscription) {
return {
diff --git a/packages/db/migrations/0082.do.add_default_subscription_status.sql b/packages/db/migrations/0082.do.add_default_subscription_status.sql
new file mode 100755
index 000000000..8683078f9
--- /dev/null
+++ b/packages/db/migrations/0082.do.add_default_subscription_status.sql
@@ -0,0 +1,10 @@
+-- Type: DO
+-- Name: add_default_subscription_status
+-- Description: Add default value to subscription status field
+
+BEGIN;
+
+ALTER TABLE omnivore.subscriptions
+ ALTER COLUMN status SET DEFAULT 'ACTIVE';
+
+COMMIT;
diff --git a/packages/db/migrations/0082.undo.add_default_subscription_status.sql b/packages/db/migrations/0082.undo.add_default_subscription_status.sql
new file mode 100755
index 000000000..c5c4771a3
--- /dev/null
+++ b/packages/db/migrations/0082.undo.add_default_subscription_status.sql
@@ -0,0 +1,9 @@
+-- Type: UNDO
+-- Name: add_default_subscription_status
+-- Description: Add default value to subscription status field
+
+BEGIN;
+
+ALTER TABLE omnivore.subscriptions ALTER status DROP DEFAULT;
+
+COMMIT;
diff --git a/packages/web/components/elements/Table.tsx b/packages/web/components/elements/Table.tsx
new file mode 100644
index 000000000..94945f1cf
--- /dev/null
+++ b/packages/web/components/elements/Table.tsx
@@ -0,0 +1,228 @@
+import { Box, HStack, SpanBox, VStack } from './LayoutPrimitives'
+import { styled } from '../tokens/stitches.config'
+import { StyledText } from './StyledText'
+import { InfoLink } from './InfoLink'
+import { Button } from './Button'
+import { Plus, Trash } from 'phosphor-react'
+import { isDarkTheme } from '../../lib/themeUpdater'
+
+interface TableProps {
+ heading: string
+ infoLink?: string
+ onAdd?: () => void
+ headers: string[]
+ rows: string[][]
+ onDelete?: (id: string) => void
+}
+
+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: '14px 0 14px 40px',
+ borderRadius: '5px 5px 0px 0px',
+ width: '100%',
+ '@md': {
+ display: 'flex',
+ },
+})
+
+const Input = styled('input', {
+ backgroundColor: 'transparent',
+ color: '$grayTextContrast',
+ marginTop: '5px',
+ '&[disabled]': {
+ border: 'none',
+ },
+})
+
+const IconButton = styled(Button, {
+ variants: {
+ style: {
+ ctaWhite: {
+ color: 'red',
+ padding: '10px',
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ border: '1px solid $grayBorder',
+ boxSizing: 'border-box',
+ borderRadius: 6,
+ width: 40,
+ height: 40,
+ },
+ },
+ },
+})
+
+export function Table(props: TableProps): JSX.Element {
+ const iconColor = isDarkTheme() ? '#D8D7D5' : '#5F5E58'
+
+ return (
+
+
+
+
+ {props.heading}
+
+ {props.infoLink && }
+ {props.onAdd && (
+
+ )}
+
+
+
+ {props.headers.map((header, index) => (
+
+
+ {header}
+
+
+ ))}
+
+ {props.rows.map((row, index) => (
+
+
+ {row.map((cell, index) => (
+
+
+
+ ))}
+ {props.onDelete && (
+ {
+ props.onDelete(row[0])
+ }}
+ >
+
+
+ )}
+
+
+ ))}
+
+ )
+}
diff --git a/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx b/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx
index 7598dcb4a..92ec8241a 100644
--- a/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx
+++ b/packages/web/lib/networking/queries/useGetSubscriptionsQuery.tsx
@@ -15,7 +15,7 @@ export type Subscription = {
status: SubscriptionStatus
createdAt: Date
updatedAt: Date
-};
+}
type SubscriptionsQueryResponse = {
isValidating: boolean
@@ -34,11 +34,12 @@ type SubscriptionsData = {
export function useGetSubscriptionsQuery(): SubscriptionsQueryResponse {
const query = gql`
query GetSubscriptions {
- subscriptions {
+ subscriptions(sort: { by: UPDATED_TIME }) {
... on SubscriptionsSuccess {
subscriptions {
id
name
+ newsletterEmail
url
description
status
diff --git a/packages/web/pages/settings/subscriptions.tsx b/packages/web/pages/settings/subscriptions.tsx
index d6a4a93b9..ec9d7cab5 100644
--- a/packages/web/pages/settings/subscriptions.tsx
+++ b/packages/web/pages/settings/subscriptions.tsx
@@ -1,23 +1,18 @@
import { useState } from 'react'
import { PrimaryLayout } from '../../components/templates/PrimaryLayout'
-import { styled } from '../../components/tokens/stitches.config'
-import { Box, VStack } from '../../components/elements/LayoutPrimitives'
import { Toaster } from 'react-hot-toast'
import { applyStoredTheme } from '../../lib/themeUpdater'
-import { StyledText } from '../../components/elements/StyledText'
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'
-
-const HeaderWrapper = styled(Box, {
- width: '100%',
-})
+import { Table } from '../../components/elements/Table'
export default function SubscriptionsPage(): JSX.Element {
const { subscriptions, revalidate } = useGetSubscriptionsQuery()
- const [confirmUnsubscribeName, setConfirmUnsubscribeName] =
- useState(null)
+ const [confirmUnsubscribeName, setConfirmUnsubscribeName] = useState<
+ string | null
+ >(null)
applyStoredTheme(false)
@@ -31,6 +26,13 @@ export default function SubscriptionsPage(): JSX.Element {
revalidate()
}
+ const headers = ['Name', 'Email', 'Updated Time']
+ const rows = subscriptions.map((subscription) => [
+ subscription.name,
+ subscription.newsletterEmail,
+ subscription.updatedAt.toString(),
+ ])
+
return (
-
- {confirmUnsubscribeName ? (
- {
- await onUnsubscribe(confirmUnsubscribeName)
- setConfirmUnsubscribeName(null)
- }}
- onOpenChange={() => setConfirmUnsubscribeName(null)}
- />
- ) : null}
-
-
-
- Subscriptions
-
-
-
- {subscriptions
- ? subscriptions.map((subscription, i) => {
- return
- })
- : null}
-
+
+ {confirmUnsubscribeName ? (
+ {
+ await onUnsubscribe(confirmUnsubscribeName)
+ setConfirmUnsubscribeName(null)
+ }}
+ onOpenChange={() => setConfirmUnsubscribeName(null)}
+ />
+ ) : null}
+
)
}