Skip to content

Commit

Permalink
feat: mark conversations as read when viewed
Browse files Browse the repository at this point in the history
  • Loading branch information
hallettj committed May 15, 2019
1 parent fec1ae7 commit 12401e9
Show file tree
Hide file tree
Showing 26 changed files with 1,023 additions and 106 deletions.
8 changes: 8 additions & 0 deletions packages/client/src/Conversation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ export default function Conversation({ accountId, conversationId }: Props) {
const { data, error, loading } = graphql.useGetConversationQuery({
variables: { id: conversationId! }
})
const setIsRead = graphql.useSetIsReadMutation({
variables: { conversationId: conversationId!, isRead: true }
})
React.useEffect(() => {
if (data && !error && !loading) {
setIsRead()
}
}, [data, error, loading, setIsRead])

// TODO: is there a way to guarantee that `accountId` and `conversationId` are available?
if (!accountId || !conversationId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,19 @@ mutation sync($accountId: ID!) {
}
}
}

mutation setIsRead($conversationId: ID!, $isRead: Boolean!) {
conversations {
setIsRead(id: $conversationId, isRead: $isRead) {
id
date
from {
host
mailbox
name
}
isRead
subject
}
}
}
182 changes: 182 additions & 0 deletions packages/client/src/generated/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ export type Conversation = {
subject?: Maybe<Scalars["String"]>
}

export type ConversationMutations = {
setIsRead: Conversation
}

export type ConversationMutationsSetIsReadArgs = {
id: Scalars["ID"]
isRead: Scalars["Boolean"]
}

export type Message = {
id: Scalars["ID"]
date: Scalars["String"]
Expand All @@ -67,6 +76,7 @@ export type Message = {

export type Mutation = {
accounts: AccountMutations
conversations: ConversationMutations
}

export type Presentable = {
Expand Down Expand Up @@ -197,6 +207,25 @@ export type SyncMutation = { __typename?: "Mutation" } & {
}
}
}

export type SetIsReadMutationVariables = {
conversationId: Scalars["ID"]
isRead: Scalars["Boolean"]
}

export type SetIsReadMutation = { __typename?: "Mutation" } & {
conversations: { __typename?: "ConversationMutations" } & {
setIsRead: { __typename?: "Conversation" } & Pick<
Conversation,
"id" | "date" | "isRead" | "subject"
> & {
from: { __typename?: "Address" } & Pick<
Address,
"host" | "mailbox" | "name"
>
}
}
}
import { DocumentNode } from "graphql"
import * as ReactApollo from "react-apollo"
import * as ReactApolloHooks from "react-apollo-hooks"
Expand Down Expand Up @@ -896,3 +925,156 @@ export function useSyncMutation(
baseOptions
)
}
export const SetIsReadDocument: DocumentNode = {
kind: "Document",
definitions: [
{
kind: "OperationDefinition",
operation: "mutation",
name: { kind: "Name", value: "setIsRead" },
variableDefinitions: [
{
kind: "VariableDefinition",
variable: {
kind: "Variable",
name: { kind: "Name", value: "conversationId" }
},
type: {
kind: "NonNullType",
type: { kind: "NamedType", name: { kind: "Name", value: "ID" } }
},
directives: []
},
{
kind: "VariableDefinition",
variable: {
kind: "Variable",
name: { kind: "Name", value: "isRead" }
},
type: {
kind: "NonNullType",
type: {
kind: "NamedType",
name: { kind: "Name", value: "Boolean" }
}
},
directives: []
}
],
directives: [],
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "Field",
name: { kind: "Name", value: "conversations" },
arguments: [],
directives: [],
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "Field",
name: { kind: "Name", value: "setIsRead" },
arguments: [
{
kind: "Argument",
name: { kind: "Name", value: "id" },
value: {
kind: "Variable",
name: { kind: "Name", value: "conversationId" }
}
},
{
kind: "Argument",
name: { kind: "Name", value: "isRead" },
value: {
kind: "Variable",
name: { kind: "Name", value: "isRead" }
}
}
],
directives: [],
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "Field",
name: { kind: "Name", value: "id" },
arguments: [],
directives: []
},
{
kind: "Field",
name: { kind: "Name", value: "date" },
arguments: [],
directives: []
},
{
kind: "Field",
name: { kind: "Name", value: "from" },
arguments: [],
directives: [],
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "Field",
name: { kind: "Name", value: "host" },
arguments: [],
directives: []
},
{
kind: "Field",
name: { kind: "Name", value: "mailbox" },
arguments: [],
directives: []
},
{
kind: "Field",
name: { kind: "Name", value: "name" },
arguments: [],
directives: []
}
]
}
},
{
kind: "Field",
name: { kind: "Name", value: "isRead" },
arguments: [],
directives: []
},
{
kind: "Field",
name: { kind: "Name", value: "subject" },
arguments: [],
directives: []
}
]
}
}
]
}
}
]
}
}
]
}
export type SetIsReadMutationFn = ReactApollo.MutationFn<
SetIsReadMutation,
SetIsReadMutationVariables
>

export function useSetIsReadMutation(
baseOptions?: ReactApolloHooks.MutationHookOptions<
SetIsReadMutation,
SetIsReadMutationVariables
>
) {
return ReactApolloHooks.useMutation<
SetIsReadMutation,
SetIsReadMutationVariables
>(SetIsReadDocument, baseOptions)
}
1 change: 1 addition & 0 deletions packages/main/codegen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ generates:
Account: ../resolvers/types#Account
AccountMutations: ../resolvers/types#AccountMutations
Conversation: ../resolvers/types#Conversation
ConversationMutations: ../resolvers/types#ConversationMutations
Message: ../resolvers/types#Message
3 changes: 2 additions & 1 deletion packages/main/migrations/002-messages.sql
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ create table message_participants(
create table message_flags(
id integer primary key,
message_id integer not null references messages(id) on delete cascade,
flag text not null
flag text not null,
unique(message_id, flag)
);

create table message_gmail_labels (
Expand Down
5 changes: 5 additions & 0 deletions packages/main/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@
"test": "jest --runInBand"
},
"dependencies": {
"@types/better-queue": "^3.8.0",
"@types/better-sqlite3": "^5.2.3",
"@types/concat-stream": "^1.6.0",
"@types/graphql": "^14.0.7",
"@types/kefir": "^3.8.1",
"@types/mailparser": "^2.4.0",
"@types/node": "^11.11.8",
"@types/node-fetch": "^2.1.7",
"@types/node-uuid": "^0.0.28",
"@types/nodemailer": "^4.6.7",
"@types/xdg-basedir": "^2.0.0",
"base64-stream": "^1.0.0",
"better-queue": "^3.8.10",
"better-sqlite3": "^5.4.0",
"better-sqlite3-helper": "^2.0.2",
"concat-stream": "^2.0.0",
Expand All @@ -42,8 +45,10 @@
"keytar": "^4.6.0",
"libqp": "^1.1.0",
"mailparser": "^2.6.0",
"mkdirp": "^0.5.1",
"moment": "^2.24.0",
"node-fetch": "^2.3.0",
"node-uuid": "^1.4.8",
"nodemailer": "^6.0.0",
"xdg-basedir": "^3.0.0",
"xoauth2": "^1.2.0"
Expand Down
5 changes: 5 additions & 0 deletions packages/main/schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ type Conversation {
subject: String
}

type ConversationMutations {
setIsRead(id: ID!, isRead: Boolean!): Conversation!
}

type Message {
id: ID!
date: String!
Expand Down Expand Up @@ -50,6 +54,7 @@ type Content {

type Mutation {
accounts: AccountMutations!
conversations: ConversationMutations!
}

type Query {
Expand Down
25 changes: 25 additions & 0 deletions packages/main/src/cache/persist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,31 @@ export function persistBody(
insertInto("message_bodies", { message_struct_id: result.id, content })
}

// TODO: What is the proper way to provide a list of values in a query?
export function addFlag({
accountId,
box,
uids,
flag
}: {
accountId: ID
box: { name: string }
uids: number[]
flag: string
}) {
db.prepare(
`
insert or ignore into message_flags (message_id, flag)
select messages.id, @flag from messages
join boxes on box_id = boxes.id
where
messages.account_id = @accountId
and messages.uid in (${uids.join(", ")})
and boxes.name = @boxName
`
).run({ accountId, boxName: box.name, flag })
}

function insertInto(table: string, values: Record<string, unknown>): ID {
const keys = Object.keys(values)
const { lastInsertRowid } = db
Expand Down
10 changes: 10 additions & 0 deletions packages/main/src/cache/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ function getBoxRecord(accountId: ID, box: { name: string }): { id: ID } | null {
.get({ account_id: accountId, name: box.name })
}

export function getBox(boxId: ID): { id: ID; name: string } | null {
return db
.prepare(
`
select id, name from boxes where id = ?
`
)
.get(boxId)
}

interface Thread {
id: string
messages: Message[]
Expand Down
1 change: 1 addition & 0 deletions packages/main/src/cache/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export type SerializedHeaders = Array<[string, HeaderValue]>

export interface Message {
id: ID
account_id: ID
box_id?: ID
date: string
envelope_date?: string
Expand Down
Loading

0 comments on commit 12401e9

Please sign in to comment.