Add button to move an email to trash.
This is the first time I'm modifying data instead of just displaying it. And this commit is a mess, it's all over the place with duplicating types and breaking my class layers. But it works, technically, so, whatever, checkpoint! I need to totally start reworking the base client library as I'm not happy with it at all. Also, it turns out that we have very little type protection on the "set" methods. I had a totally improper signature for about an hour that led to useless debugging. Reading the standard, which is excellent, helped me get sorted out, but they type checker should be helping me. Additionally, I should be creating this Account class type within the client.
This commit is contained in:
parent
dfca32eb36
commit
1e9dae15f1
|
@ -1,3 +1,7 @@
|
|||
import { Trash } from "react-bootstrap-icons";
|
||||
import Button from "react-bootstrap/Button";
|
||||
import ButtonGroup from "react-bootstrap/ButtonGroup";
|
||||
import ButtonToolbar from "react-bootstrap/ButtonToolbar";
|
||||
import Placeholder from "react-bootstrap/Placeholder";
|
||||
import React from "react";
|
||||
|
||||
|
@ -55,6 +59,21 @@ class EmailSummary extends React.Component<
|
|||
stub.subject}
|
||||
</span>
|
||||
</a>
|
||||
<ButtonToolbar>
|
||||
<ButtonGroup className="me-2">
|
||||
<Button
|
||||
onClick={() => {
|
||||
this.props.client.emailMoveTrash(
|
||||
this.props.account,
|
||||
this.props.emailId,
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Trash />
|
||||
</Button>
|
||||
<Button>2</Button>
|
||||
</ButtonGroup>
|
||||
</ButtonToolbar>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,19 @@
|
|||
* None of the dependencies should leak, in types or otherwise
|
||||
*/
|
||||
import * as base64 from "base-64";
|
||||
import * as jmaptypes from "./jmap-client-ts/src/types";
|
||||
import * as jmapclient from "./jmap-client-ts/src";
|
||||
import { FetchTransport } from "./jmap-client-ts/src/utils/fetch-transport";
|
||||
|
||||
import { IAccount, IEmail, IEmailStub, IMailbox, ISession } from "./types";
|
||||
import {
|
||||
IAccount,
|
||||
IEmail,
|
||||
IEmailStub,
|
||||
IMailbox,
|
||||
ISession,
|
||||
MailboxRole,
|
||||
PushMessage,
|
||||
} from "./types";
|
||||
|
||||
type Callback = () => void;
|
||||
|
||||
|
@ -21,9 +30,40 @@ export interface ClientState {
|
|||
emailStubs: Set<string>;
|
||||
mailboxes: Set<string>;
|
||||
};
|
||||
mailboxes: {
|
||||
trash: IMailbox;
|
||||
} | null;
|
||||
session: ISession | null;
|
||||
}
|
||||
|
||||
class Account implements IAccount {
|
||||
id: string;
|
||||
|
||||
accountCapabilities: { [key: string]: jmaptypes.IMailCapabilities };
|
||||
isPersonal: boolean;
|
||||
isReadOnly: boolean;
|
||||
mailboxes: Array<IMailbox> | null;
|
||||
name: string;
|
||||
|
||||
constructor(id: string, props: jmaptypes.IAccount) {
|
||||
this.id = id;
|
||||
this.accountCapabilities = props.accountCapabilities;
|
||||
this.isPersonal = props.isPersonal;
|
||||
this.isReadOnly = props.isReadOnly;
|
||||
this.mailboxes = null;
|
||||
this.name = props.name;
|
||||
}
|
||||
mailboxByRole(role: MailboxRole): IMailbox | null {
|
||||
if (this.mailboxes === null) return null;
|
||||
for (let i = 0; i < this.mailboxes.length; i++) {
|
||||
const m = this.mailboxes[i];
|
||||
if (m.role === role) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
export default class Client {
|
||||
// All objects which currently are listening for changes
|
||||
callbacks: Array<Callback> = [];
|
||||
|
@ -34,6 +74,7 @@ export default class Client {
|
|||
emailStubs: new Set(),
|
||||
mailboxes: new Set(),
|
||||
},
|
||||
mailboxes: null,
|
||||
session: null,
|
||||
};
|
||||
|
||||
|
@ -67,6 +108,43 @@ export default class Client {
|
|||
return;
|
||||
}
|
||||
|
||||
emailMoveTrash(account: IAccount, emailId: string) {
|
||||
if (this.jclient === null) return;
|
||||
console.log("Trashing", emailId);
|
||||
const email = this.emailStub(emailId);
|
||||
if (email === null) return;
|
||||
const trashMailbox = account.mailboxByRole("trash");
|
||||
if (trashMailbox === null) {
|
||||
console.error(
|
||||
"Cannot trash ",
|
||||
emailId,
|
||||
" because ",
|
||||
account.id,
|
||||
" does not have a 'trash' mailbox",
|
||||
);
|
||||
return;
|
||||
}
|
||||
let mailboxIds = Object.keys(email.mailboxIds).reduce(
|
||||
(acc, key) => {
|
||||
acc[key as keyof typeof email.mailboxIds] = false;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<keyof typeof email.mailboxIds, boolean>,
|
||||
);
|
||||
mailboxIds[trashMailbox.id] = true;
|
||||
const props = {
|
||||
accountId: account.id,
|
||||
update: {
|
||||
[email.id]: {
|
||||
mailboxIds: mailboxIds,
|
||||
},
|
||||
},
|
||||
};
|
||||
this.jclient.email_set(props).then((response) => {
|
||||
console.log("Trashed", emailId);
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure we have the full email content
|
||||
ensureEmailContent(accountId: string, emailId: string) {
|
||||
if (this.state.session == null) return;
|
||||
|
@ -98,7 +176,9 @@ export default class Client {
|
|||
|
||||
email(emailId: string): IEmail | null {
|
||||
if (this.state.session == null) return null;
|
||||
return this.state.session.emails[emailId];
|
||||
const result = this.state.session.emails[emailId];
|
||||
if (result === undefined) return null;
|
||||
return result;
|
||||
}
|
||||
|
||||
emailGetContent(accountId: string, emailId: string) {
|
||||
|
@ -148,7 +228,7 @@ export default class Client {
|
|||
.email_get({
|
||||
accountId: accountId,
|
||||
ids: [emailId],
|
||||
properties: ["from", "receivedAt", "subject"],
|
||||
properties: ["from", "mailboxIds", "receivedAt", "subject"],
|
||||
})
|
||||
.then((response) => {
|
||||
console.log(msg, "response", response);
|
||||
|
@ -163,6 +243,7 @@ export default class Client {
|
|||
this.state.session.emailStubs[e.id] = {
|
||||
from: e.from,
|
||||
id: e.id,
|
||||
mailboxIds: e.mailboxIds,
|
||||
receivedAt: e.receivedAt,
|
||||
subject: e.subject,
|
||||
};
|
||||
|
@ -272,7 +353,7 @@ export default class Client {
|
|||
accounts: Object.fromEntries(
|
||||
Object.entries(session.accounts).map(([key, account]) => [
|
||||
key,
|
||||
{ ...account, id: key.toString(), mailboxes: null },
|
||||
new Account(key.toString(), account),
|
||||
]),
|
||||
),
|
||||
emails: {},
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import * as client from "./jmap-client-ts/src/types";
|
||||
|
||||
export type MailboxIdMap = { [mailboxId: string]: boolean };
|
||||
export interface IEmailStub {
|
||||
from: Array<client.IEmailAddress> | null;
|
||||
id: string;
|
||||
mailboxIds: MailboxIdMap;
|
||||
receivedAt: string;
|
||||
subject: string;
|
||||
}
|
||||
|
@ -18,8 +20,20 @@ export interface IEmail extends client.IEmailProperties {
|
|||
export interface IAccount extends client.IAccount {
|
||||
id: string;
|
||||
mailboxes: Array<IMailbox> | null;
|
||||
}
|
||||
|
||||
mailboxByRole(role: MailboxRole): IMailbox | null;
|
||||
}
|
||||
export type MailboxRole =
|
||||
| "all"
|
||||
| "archive"
|
||||
| "drafts"
|
||||
| "flagged"
|
||||
| "important"
|
||||
| "junk"
|
||||
| "sent"
|
||||
| "subscribed"
|
||||
| "trash";
|
||||
export type PushMessage = client.PushMessage;
|
||||
export type AccountIdMap = { [accountId: string]: IAccount };
|
||||
export type EmailStubIdMap = { [emailId: string]: IEmailStub };
|
||||
export type EmailIdMap = { [emailId: string]: IEmail };
|
||||
|
|
Loading…
Reference in New Issue