Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: bulletin #3251

Merged
merged 5 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions app/components/notifications/bulletins.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from "react"
import { Linking } from "react-native"

import { useNotifications } from "."
import { NotificationCardUI } from "./notification-card-ui"
import {
BulletinsDocument,
BulletinsQuery,
useStatefulNotificationAcknowledgeMutation,
} from "@app/graphql/generated"
import { BLINK_DEEP_LINK_PREFIX } from "@app/config"

type Props = {
loading: boolean
bulletins: BulletinsQuery | undefined
}

export const BulletinsCard: React.FC<Props> = ({ loading, bulletins }) => {
const { cardInfo } = useNotifications()

const [ack, { loading: ackLoading }] = useStatefulNotificationAcknowledgeMutation({
refetchQueries: [BulletinsDocument],
})

if (loading) return null

if (
bulletins &&
bulletins.me?.unacknowledgedStatefulNotificationsWithBulletinEnabled?.edges &&
bulletins.me?.unacknowledgedStatefulNotificationsWithBulletinEnabled?.edges.length > 0
) {
return (
<>
{bulletins.me?.unacknowledgedStatefulNotificationsWithBulletinEnabled?.edges.map(
({ node: bulletin }) => (
<NotificationCardUI
key={bulletin.id}
title={bulletin.title}
text={bulletin.body}
action={async () => {
ack({ variables: { input: { notificationId: bulletin.id } } })
if (bulletin.action?.__typename === "OpenDeepLinkAction")
Linking.openURL(BLINK_DEEP_LINK_PREFIX + bulletin.action.deepLink)
else if (bulletin.action?.__typename === "OpenExternalLinkAction")
Linking.openURL(bulletin.action.url)
}}
dismissAction={() =>
ack({ variables: { input: { notificationId: bulletin.id } } })
}
loading={ackLoading}
/>
),
)}
</>
)
}

if (!cardInfo) {
return null
}

return (
<NotificationCardUI
title={cardInfo.title}
text={cardInfo.text}
icon={cardInfo.icon}
action={cardInfo.action}
loading={cardInfo.loading}
dismissAction={cardInfo.dismissAction}
/>
)
}
20 changes: 0 additions & 20 deletions app/components/notifications/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Text, makeStyles, useTheme } from "@rneui/themed"

import { GaloyIcon, IconNamesType } from "../atomic/galoy-icon"
import CustomModal from "../custom-modal/custom-modal"
import { NotificationCardUI } from "./notification-card-ui"

type NotifyModalArgs = {
title: string
Expand Down Expand Up @@ -211,23 +210,4 @@ const useStyles = makeStyles(() => ({
},
}))

export const NotificationCard = () => {
const { cardInfo } = useNotifications()

if (!cardInfo) {
return null
}

return (
<NotificationCardUI
title={cardInfo.title}
text={cardInfo.text}
icon={cardInfo.icon}
action={cardInfo.action}
loading={cardInfo.loading}
dismissAction={cardInfo.dismissAction}
/>
)
}

export const useNotifications = () => useContext(NotificationModalContext)
2 changes: 2 additions & 0 deletions app/config/appinfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ export const getInviteLink = (_username: string | null | undefined) => {
const username = _username ? `/${_username}` : ""
return `https://get.blink.sv${username}`
}

export const BLINK_DEEP_LINK_PREFIX = "blink:/"
59 changes: 56 additions & 3 deletions app/graphql/generated.gql
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,49 @@ mutation userUpdateUsername($input: UserUpdateUsernameInput!) {
}
}

query Bulletins($first: Int!, $after: String) {
me {
unacknowledgedStatefulNotificationsWithBulletinEnabled(
first: $first
after: $after
) {
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
__typename
}
edges {
node {
id
title
body
createdAt
acknowledgedAt
bulletinEnabled
action {
... on OpenDeepLinkAction {
deepLink
__typename
}
... on OpenExternalLinkAction {
url
__typename
}
__typename
}
__typename
}
cursor
__typename
}
__typename
}
__typename
}
}

query Circles {
me {
id
Expand Down Expand Up @@ -859,15 +902,25 @@ query SettingsScreen {

query StatefulNotifications($after: String) {
me {
statefulNotifications(first: 10, after: $after) {
statefulNotificationsWithoutBulletinEnabled(first: 10, after: $after) {
nodes {
id
title
body
deepLink
createdAt
acknowledgedAt
bulletinEnabled
action {
... on OpenDeepLinkAction {
deepLink
__typename
}
... on OpenExternalLinkAction {
url
__typename
}
__typename
}
__typename
}
pageInfo {
Expand All @@ -886,7 +939,7 @@ query StatefulNotifications($after: String) {
query UnacknowledgedNotificationCount {
me {
id
unacknowledgedStatefulNotificationsCount
unacknowledgedStatefulNotificationsWithoutBulletinEnabledCount
__typename
}
}
Expand Down
107 changes: 100 additions & 7 deletions app/graphql/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2173,11 +2173,12 @@ export type User = {
/** Phone number with international calling code. */
readonly phone?: Maybe<Scalars['Phone']['output']>;
readonly statefulNotifications: StatefulNotificationConnection;
readonly statefulNotificationsWithoutBulletinEnabled: StatefulNotificationConnection;
readonly supportChat: ReadonlyArray<SupportMessage>;
/** Whether TOTP is enabled for this user. */
readonly totpEnabled: Scalars['Boolean']['output'];
readonly unacknowledgedStatefulNotificationsCount: Scalars['Int']['output'];
readonly unacknowledgedStatefulNotificationsWithBulletinEnabled: StatefulNotificationConnection;
readonly unacknowledgedStatefulNotificationsWithoutBulletinEnabledCount: Scalars['Int']['output'];
/**
* Optional immutable user friendly identifier.
* @deprecated will be moved to @Handle in Account and Wallet
Expand All @@ -2197,6 +2198,12 @@ export type UserStatefulNotificationsArgs = {
};


export type UserStatefulNotificationsWithoutBulletinEnabledArgs = {
after?: InputMaybe<Scalars['String']['input']>;
first: Scalars['Int']['input'];
};


export type UserUnacknowledgedStatefulNotificationsWithBulletinEnabledArgs = {
after?: InputMaybe<Scalars['String']['input']>;
first: Scalars['Int']['input'];
Expand Down Expand Up @@ -2677,6 +2684,14 @@ export type HomeUnauthedQueryVariables = Exact<{ [key: string]: never; }>;

export type HomeUnauthedQuery = { readonly __typename: 'Query', readonly globals?: { readonly __typename: 'Globals', readonly network: Network } | null, readonly currencyList: ReadonlyArray<{ readonly __typename: 'Currency', readonly id: string, readonly flag: string, readonly name: string, readonly symbol: string, readonly fractionDigits: number }> };

export type BulletinsQueryVariables = Exact<{
first: Scalars['Int']['input'];
after?: InputMaybe<Scalars['String']['input']>;
}>;


export type BulletinsQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly unacknowledgedStatefulNotificationsWithBulletinEnabled: { readonly __typename: 'StatefulNotificationConnection', readonly pageInfo: { readonly __typename: 'PageInfo', readonly endCursor?: string | null, readonly hasNextPage: boolean, readonly hasPreviousPage: boolean, readonly startCursor?: string | null }, readonly edges: ReadonlyArray<{ readonly __typename: 'StatefulNotificationEdge', readonly cursor: string, readonly node: { readonly __typename: 'StatefulNotification', readonly id: string, readonly title: string, readonly body: string, readonly createdAt: number, readonly acknowledgedAt?: number | null, readonly bulletinEnabled: boolean, readonly action?: { readonly __typename: 'OpenDeepLinkAction', readonly deepLink: string } | { readonly __typename: 'OpenExternalLinkAction', readonly url: string } | null } }> } } | null };

export type BusinessMapMarkersQueryVariables = Exact<{ [key: string]: never; }>;


Expand All @@ -2687,7 +2702,7 @@ export type StatefulNotificationsQueryVariables = Exact<{
}>;


export type StatefulNotificationsQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly statefulNotifications: { readonly __typename: 'StatefulNotificationConnection', readonly nodes: ReadonlyArray<{ readonly __typename: 'StatefulNotification', readonly id: string, readonly title: string, readonly body: string, readonly deepLink?: string | null, readonly createdAt: number, readonly acknowledgedAt?: number | null, readonly bulletinEnabled: boolean }>, readonly pageInfo: { readonly __typename: 'PageInfo', readonly endCursor?: string | null, readonly hasNextPage: boolean, readonly hasPreviousPage: boolean, readonly startCursor?: string | null } } } | null };
export type StatefulNotificationsQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly statefulNotificationsWithoutBulletinEnabled: { readonly __typename: 'StatefulNotificationConnection', readonly nodes: ReadonlyArray<{ readonly __typename: 'StatefulNotification', readonly id: string, readonly title: string, readonly body: string, readonly createdAt: number, readonly acknowledgedAt?: number | null, readonly bulletinEnabled: boolean, readonly action?: { readonly __typename: 'OpenDeepLinkAction', readonly deepLink: string } | { readonly __typename: 'OpenExternalLinkAction', readonly url: string } | null }>, readonly pageInfo: { readonly __typename: 'PageInfo', readonly endCursor?: string | null, readonly hasNextPage: boolean, readonly hasPreviousPage: boolean, readonly startCursor?: string | null } } } | null };

export type StatefulNotificationAcknowledgeMutationVariables = Exact<{
input: StatefulNotificationAcknowledgeInput;
Expand Down Expand Up @@ -3062,7 +3077,7 @@ export type AccountDisableNotificationCategoryMutation = { readonly __typename:
export type UnacknowledgedNotificationCountQueryVariables = Exact<{ [key: string]: never; }>;


export type UnacknowledgedNotificationCountQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly unacknowledgedStatefulNotificationsCount: number } | null };
export type UnacknowledgedNotificationCountQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly unacknowledgedStatefulNotificationsWithoutBulletinEnabledCount: number } | null };

export type SettingsScreenQueryVariables = Exact<{ [key: string]: never; }>;

Expand Down Expand Up @@ -4761,6 +4776,76 @@ export type HomeUnauthedQueryHookResult = ReturnType<typeof useHomeUnauthedQuery
export type HomeUnauthedLazyQueryHookResult = ReturnType<typeof useHomeUnauthedLazyQuery>;
export type HomeUnauthedSuspenseQueryHookResult = ReturnType<typeof useHomeUnauthedSuspenseQuery>;
export type HomeUnauthedQueryResult = Apollo.QueryResult<HomeUnauthedQuery, HomeUnauthedQueryVariables>;
export const BulletinsDocument = gql`
query Bulletins($first: Int!, $after: String) {
me {
unacknowledgedStatefulNotificationsWithBulletinEnabled(
first: $first
after: $after
) {
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
}
edges {
node {
id
title
body
createdAt
acknowledgedAt
bulletinEnabled
action {
... on OpenDeepLinkAction {
deepLink
}
... on OpenExternalLinkAction {
url
}
}
}
cursor
}
}
}
}
`;

/**
* __useBulletinsQuery__
*
* To run a query within a React component, call `useBulletinsQuery` and pass it any options that fit your needs.
* When your component renders, `useBulletinsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useBulletinsQuery({
* variables: {
* first: // value for 'first'
* after: // value for 'after'
* },
* });
*/
export function useBulletinsQuery(baseOptions: Apollo.QueryHookOptions<BulletinsQuery, BulletinsQueryVariables> & ({ variables: BulletinsQueryVariables; skip?: boolean; } | { skip: boolean; }) ) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<BulletinsQuery, BulletinsQueryVariables>(BulletinsDocument, options);
}
export function useBulletinsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<BulletinsQuery, BulletinsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<BulletinsQuery, BulletinsQueryVariables>(BulletinsDocument, options);
}
export function useBulletinsSuspenseQuery(baseOptions?: Apollo.SuspenseQueryHookOptions<BulletinsQuery, BulletinsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<BulletinsQuery, BulletinsQueryVariables>(BulletinsDocument, options);
}
export type BulletinsQueryHookResult = ReturnType<typeof useBulletinsQuery>;
export type BulletinsLazyQueryHookResult = ReturnType<typeof useBulletinsLazyQuery>;
export type BulletinsSuspenseQueryHookResult = ReturnType<typeof useBulletinsSuspenseQuery>;
export type BulletinsQueryResult = Apollo.QueryResult<BulletinsQuery, BulletinsQueryVariables>;
export const BusinessMapMarkersDocument = gql`
query businessMapMarkers {
businessMapMarkers {
Expand Down Expand Up @@ -4810,15 +4895,22 @@ export type BusinessMapMarkersQueryResult = Apollo.QueryResult<BusinessMapMarker
export const StatefulNotificationsDocument = gql`
query StatefulNotifications($after: String) {
me {
statefulNotifications(first: 10, after: $after) {
statefulNotificationsWithoutBulletinEnabled(first: 10, after: $after) {
nodes {
id
title
body
deepLink
createdAt
acknowledgedAt
bulletinEnabled
action {
... on OpenDeepLinkAction {
deepLink
}
... on OpenExternalLinkAction {
url
}
}
}
pageInfo {
endCursor
Expand Down Expand Up @@ -7255,7 +7347,7 @@ export const UnacknowledgedNotificationCountDocument = gql`
query UnacknowledgedNotificationCount {
me {
id
unacknowledgedStatefulNotificationsCount
unacknowledgedStatefulNotificationsWithoutBulletinEnabledCount
}
}
`;
Expand Down Expand Up @@ -9404,10 +9496,11 @@ export type UserResolvers<ContextType = any, ParentType extends ResolversParentT
language?: Resolver<ResolversTypes['Language'], ParentType, ContextType>;
phone?: Resolver<Maybe<ResolversTypes['Phone']>, ParentType, ContextType>;
statefulNotifications?: Resolver<ResolversTypes['StatefulNotificationConnection'], ParentType, ContextType, RequireFields<UserStatefulNotificationsArgs, 'first'>>;
statefulNotificationsWithoutBulletinEnabled?: Resolver<ResolversTypes['StatefulNotificationConnection'], ParentType, ContextType, RequireFields<UserStatefulNotificationsWithoutBulletinEnabledArgs, 'first'>>;
supportChat?: Resolver<ReadonlyArray<ResolversTypes['SupportMessage']>, ParentType, ContextType>;
totpEnabled?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
unacknowledgedStatefulNotificationsCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
unacknowledgedStatefulNotificationsWithBulletinEnabled?: Resolver<ResolversTypes['StatefulNotificationConnection'], ParentType, ContextType, RequireFields<UserUnacknowledgedStatefulNotificationsWithBulletinEnabledArgs, 'first'>>;
unacknowledgedStatefulNotificationsWithoutBulletinEnabledCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
username?: Resolver<Maybe<ResolversTypes['Username']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
Expand Down
Loading
Loading