Merge pull request #2572 from omnivore-app/feature/pause-rss-feed

add a button to pause rss feed
This commit is contained in:
Hongbo Wu 2023-08-03 13:33:11 +08:00 committed by GitHub
commit 55e378c9b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 119 additions and 41 deletions

View file

@ -3031,6 +3031,7 @@ export type UpdateSubscriptionInput = {
id: Scalars['ID'];
lastFetchedAt?: InputMaybe<Scalars['Date']>;
name?: InputMaybe<Scalars['String']>;
status?: InputMaybe<SubscriptionStatus>;
};
export type UpdateSubscriptionResult = UpdateSubscriptionError | UpdateSubscriptionSuccess;

View file

@ -2353,6 +2353,7 @@ input UpdateSubscriptionInput {
id: ID!
lastFetchedAt: Date
name: String
status: SubscriptionStatus
}
union UpdateSubscriptionResult = UpdateSubscriptionError | UpdateSubscriptionSuccess

View file

@ -47,49 +47,61 @@ export const subscriptionsResolver = authorized<
SubscriptionsSuccessPartial,
SubscriptionsError,
QuerySubscriptionsArgs
>(async (_obj, { sort, type: subscriptionType }, { claims: { uid }, log }) => {
log.info('subscriptionsResolver')
>(
async (
_obj,
{ sort, type = SubscriptionType.Newsletter }, // default to newsletter
{ claims: { uid }, log }
) => {
log.info('subscriptionsResolver')
analytics.track({
userId: uid,
event: 'subscriptions',
properties: {
env: env.server.apiEnv,
},
})
analytics.track({
userId: uid,
event: 'subscriptions',
properties: {
env: env.server.apiEnv,
},
})
try {
const sortBy =
sort?.by === SortBy.UpdatedTime ? 'lastFetchedAt' : 'createdAt'
const sortOrder = sort?.order === SortOrder.Ascending ? 'ASC' : 'DESC'
const user = await getRepository(User).findOneBy({ id: uid })
if (!user) {
return {
errorCodes: [SubscriptionsErrorCode.Unauthorized],
}
}
const queryBuilder = getRepository(Subscription)
.createQueryBuilder('subscription')
.leftJoinAndSelect('subscription.newsletterEmail', 'newsletterEmail')
.where({
user: { id: uid },
type,
})
// only return active subscriptions for newsletter
if (type === SubscriptionType.Newsletter) {
queryBuilder.andWhere({ status: SubscriptionStatus.Active })
}
const subscriptions = await queryBuilder
.orderBy('subscription.' + sortBy, sortOrder)
.getMany()
try {
const sortBy =
sort?.by === SortBy.UpdatedTime ? 'lastFetchedAt' : 'createdAt'
const sortOrder = sort?.order === SortOrder.Ascending ? 'ASC' : 'DESC'
const user = await getRepository(User).findOneBy({ id: uid })
if (!user) {
return {
errorCodes: [SubscriptionsErrorCode.Unauthorized],
subscriptions,
}
} catch (error) {
log.error(error)
return {
errorCodes: [SubscriptionsErrorCode.BadRequest],
}
}
const subscriptions = await getRepository(Subscription)
.createQueryBuilder('subscription')
.leftJoinAndSelect('subscription.newsletterEmail', 'newsletterEmail')
.where({
user: { id: uid },
status: SubscriptionStatus.Active,
type: subscriptionType || SubscriptionType.Newsletter, // default to newsletter
})
.orderBy('subscription.' + sortBy, sortOrder)
.getMany()
return {
subscriptions,
}
} catch (error) {
log.error(error)
return {
errorCodes: [SubscriptionsErrorCode.BadRequest],
}
}
})
)
export type UnsubscribeSuccessPartial = Merge<
UnsubscribeSuccess,
@ -318,7 +330,6 @@ export const updateSubscriptionResolver = authorized<
const subscription = await getRepository(Subscription).findOneBy({
id: input.id,
user: { id: uid },
status: SubscriptionStatus.Active,
})
if (!subscription) {
log.info('subscription not found')
@ -335,6 +346,7 @@ export const updateSubscriptionResolver = authorized<
lastFetchedAt: input.lastFetchedAt
? new Date(input.lastFetchedAt)
: undefined,
status: input.status || undefined,
})
return {

View file

@ -2511,6 +2511,7 @@ const schema = gql`
name: String
description: String
lastFetchedAt: Date
status: SubscriptionStatus
}
union UpdateSubscriptionResult =

View file

@ -1,6 +1,9 @@
import { gql } from 'graphql-request'
import { gqlFetcher } from '../networkHelpers'
import { Subscription } from '../queries/useGetSubscriptionsQuery'
import {
Subscription,
SubscriptionStatus,
} from '../queries/useGetSubscriptionsQuery'
interface UpdateSubscriptionResult {
updateSubscription: UpdateSubscription
@ -22,6 +25,7 @@ interface UpdateSubscriptionInput {
lastFetchedAt?: Date
name?: string
description?: string
status?: SubscriptionStatus
}
export async function updateSubscriptionMutation(

View file

@ -8,15 +8,16 @@ import { ConfirmationModal } from '../../../components/patterns/ConfirmationModa
import {
EmptySettingsRow,
SettingsTable,
SettingsTableRow,
SettingsTableRow
} from '../../../components/templates/settings/SettingsTable'
import { theme } from '../../../components/tokens/stitches.config'
import { formattedDateTime } from '../../../lib/dateFormatting'
import { unsubscribeMutation } from '../../../lib/networking/mutations/unsubscribeMutation'
import { updateSubscriptionMutation } from '../../../lib/networking/mutations/updateSubscriptionMutation'
import {
SubscriptionStatus,
SubscriptionType,
useGetSubscriptionsQuery,
useGetSubscriptionsQuery
} from '../../../lib/networking/queries/useGetSubscriptionsQuery'
import { applyStoredTheme } from '../../../lib/themeUpdater'
import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers'
@ -30,6 +31,8 @@ export default function Rss(): JSX.Element {
const [onDeleteId, setOnDeleteId] = useState<string>('')
const [onEditId, setOnEditId] = useState('')
const [onEditName, setOnEditName] = useState('')
const [onPauseId, setOnPauseId] = useState('')
const [onEditStatus, setOnEditStatus] = useState<SubscriptionStatus>()
async function updateSubscription(): Promise<void> {
const result = await updateSubscriptionMutation({
@ -61,6 +64,27 @@ export default function Rss(): JSX.Element {
revalidate()
}
async function onPause(
id: string,
status: SubscriptionStatus = 'UNSUBSCRIBED'
): Promise<void> {
const result = await updateSubscriptionMutation({
id,
status,
})
const action = status == 'UNSUBSCRIBED' ? 'pause' : 'resume'
if (result) {
showSuccessToast(`RSS feed ${action}d`, {
position: 'bottom-right',
})
} else {
showErrorToast(`Failed to ${action}`, { position: 'bottom-right' })
}
revalidate()
}
applyStoredTheme(false)
return (
@ -152,7 +176,14 @@ export default function Rss(): JSX.Element {
console.log('onDelete triggered: ', subscription.id)
setOnDeleteId(subscription.id)
}}
onEdit={() => {
setOnEditStatus(
subscription.status == 'ACTIVE' ? 'UNSUBSCRIBED' : 'ACTIVE'
)
setOnPauseId(subscription.id)
}}
deleteTitle="Delete"
editTitle={subscription.status === 'ACTIVE' ? 'Pause' : 'Resume'}
sublineElement={
<StyledText
css={{
@ -171,6 +202,15 @@ export default function Rss(): JSX.Element {
onClick={() => {
router.push(`/home?q=in:inbox rss:"${subscription.url}"`)
}}
extraElement={
<StyledText
css={{
fontSize: '12px',
}}
>
{subscription.status === 'ACTIVE' ? 'Active' : 'Paused'}
</StyledText>
}
/>
)
})
@ -188,6 +228,25 @@ export default function Rss(): JSX.Element {
onOpenChange={() => setOnDeleteId('')}
/>
)}
{onPauseId && (
<ConfirmationModal
message={`RSS feed will be ${
onEditStatus === 'UNSUBSCRIBED' ? 'paused' : 'resumed'
}. You can ${
onEditStatus === 'UNSUBSCRIBED' ? 'resume' : 'pause'
} it at any time.`}
onAccept={async () => {
await onPause(onPauseId, onEditStatus)
setOnPauseId('')
setOnEditStatus(undefined)
}}
onOpenChange={() => {
setOnPauseId('')
setOnEditStatus(undefined)
}}
/>
)}
</SettingsTable>
)
}