diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index ac018ff..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "src/jmap-client-ts"] - path = src/client/jmap-client-ts - url = git@github.com:EliRibble/jmap-client-ts.git diff --git a/package-lock.json b/package-lock.json index 8121cc1..89f11c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,14 +16,13 @@ "@types/node": "^16.18.104", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", - "axios": "^0.21.4", "base-64": "^1.0.0", "bootstrap": "^5.3.3", + "jmap-client-ts": "^1.0.0", "react": "^18.3.1", "react-bootstrap": "^2.10.4", "react-dom": "^18.3.1", "react-scripts": "5.0.1", - "sass": "^1.77.8", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, @@ -5257,14 +5256,6 @@ "node": ">=4" } }, - "node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, "node_modules/axobject-query": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", @@ -9328,11 +9319,6 @@ "url": "https://opencollective.com/immer" } }, - "node_modules/immutable": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", - "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==" - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -12007,6 +11993,11 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jmap-client-ts": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jmap-client-ts/-/jmap-client-ts-1.0.0.tgz", + "integrity": "sha512-qL31lYUpLAqrVFMaMsogorcAcpZRTSjWPwnxdl61mDNY9DINQvrKIkYCMstva4cxTbL1kQFG4aT8K9wOesrj7g==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -15533,22 +15524,6 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, - "node_modules/sass": { - "version": "1.77.8", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz", - "integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==", - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/sass-loader": { "version": "12.6.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", diff --git a/package.json b/package.json index 6627f40..9247a49 100644 --- a/package.json +++ b/package.json @@ -11,14 +11,13 @@ "@types/node": "^16.18.104", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", - "axios": "^0.21.4", "base-64": "^1.0.0", "bootstrap": "^5.3.3", + "jmap-client-ts": "^1.0.0", "react": "^18.3.1", "react-bootstrap": "^2.10.4", "react-dom": "^18.3.1", "react-scripts": "5.0.1", - "sass": "^1.77.8", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, diff --git a/src/App.tsx b/src/App.tsx index 78eec8c..a76caf9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,15 +1,14 @@ import "./App.css"; -import "./style.scss"; +import "bootstrap/dist/css/bootstrap.min.css"; import Client, { IAuth } from "./client/Client"; -import { AccountIdMap, IAccount, IEmail, IMailbox } from "./client/types"; +import { AccountIdMap, IAccount, IMailbox } from "./client/types"; import AppLayout from "./AppLayout"; import AuthModal from "./AuthModal"; import React from "react"; interface ILocation { accountId: string; - emailId: string; mailboxId: string; } @@ -17,7 +16,6 @@ type AppState = { auth: IAuth; account: IAccount | null; accounts: AccountIdMap; - email: IEmail | null; location: ILocation; mailbox: IMailbox | null; }; @@ -39,8 +37,7 @@ class App extends React.Component { account: null, accounts: {}, auth: { email: "", password: "" }, - email: null, - location: { accountId: "", emailId: "", mailboxId: "" }, + location: { accountId: "", mailboxId: "" }, mailbox: null, }; @@ -49,20 +46,14 @@ class App extends React.Component { const parts = hash.split("/"); const accountId = parts[0]; const mailboxId = parts[1]; - const emailId = parts[2]; this.setState({ ...this.state, account: this.account(), - email: this.client.email(emailId), location: { accountId: accountId, - emailId: emailId, mailboxId: mailboxId, }, - mailbox: this.client.mailbox(accountId, mailboxId), }); - if (!this.state.account) return; - this.client.ensureEmailList(accountId, mailboxId); } // When the user provides credentials @@ -79,6 +70,16 @@ class App extends React.Component { this.client.doLogin({ email, password }); } + onMailboxSelect(mailboxId: string) { + if (!this.state.account) return; + this.client.emailList(this.state.account.id, mailboxId, []); + this.setState({ + ...this.state, + mailbox: this.client.mailbox(this.state.account.id, mailboxId), + }); + window.location.hash = this.state.location.accountId + "/" + mailboxId; + } + // Load up auth credentials from the local store loadAuth() { const data = localStorage.getItem("auth"); @@ -108,7 +109,6 @@ class App extends React.Component { accounts: this.client.state.session ? this.client.state.session.accounts : {}, - email: this.client.email(this.state.location.emailId), mailbox: this.mailbox(), }); }); @@ -131,9 +131,10 @@ class App extends React.Component { account={this.state.account} accounts={this.state.accounts} client={this.client} - email={this.state.email} - emailId={this.state.location.emailId} mailbox={this.state.mailbox} + onMailboxSelect={(m) => { + this.onMailboxSelect(m); + }} /> void; }; const AppLayout: React.FC = (props) => { return ( - + @@ -30,14 +29,16 @@ const AppLayout: React.FC = (props) => { - - - - + + + diff --git a/src/EmailArea.tsx b/src/EmailArea.tsx deleted file mode 100644 index 3d3c049..0000000 --- a/src/EmailArea.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React from "react"; -import Stack from "react-bootstrap/Stack"; - -import { IAccount, IEmail, IMailbox } from "./client/types"; -import Client from "./client/Client"; -import EmailContent from "./EmailContent"; -import EmailList from "./EmailList"; - -type EmailAreaProps = { - account: IAccount | null; - client: Client; - email: IEmail | null; - emailId: string; - mailbox: IMailbox | null; -}; - -const EmailArea: React.FC = (props) => { - if (props.emailId === "") { - return ( - - ); - } else { - return ( - - - - - ); - } -}; -export default EmailArea; diff --git a/src/EmailContent.tsx b/src/EmailContent.tsx deleted file mode 100644 index 953d043..0000000 --- a/src/EmailContent.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import Button from "react-bootstrap/Button"; -import Col from "react-bootstrap/Col"; -import Container from "react-bootstrap/Container"; -import Form from "react-bootstrap/Form"; -import Placeholder from "react-bootstrap/Placeholder"; -import React from "react"; -import Row from "react-bootstrap/Row"; - -import Client from "./client/Client"; -import EmailContentHTML from "./EmailContentHTML"; -import EmailContentText from "./EmailContentText"; -import { IAccount, IEmail } from "./client/types"; - -type EmailContentProps = { - account: IAccount | null; - client: Client | null; - email: IEmail | null; - emailId: string; -}; - -type EmailContentState = { - showHTML: boolean; -}; - -class EmailContent extends React.Component< - EmailContentProps, - EmailContentState -> { - state = { - showHTML: false, - }; - - componentDidMount() { - this.ensureData(); - } - componentDidUpdate() { - this.ensureData(); - } - - ensureData() { - if (this.props.account == null) return; - if (this.props.client == null) return; - this.props.client.ensureEmailContent( - this.props.account.id, - this.props.emailId, - ); - } - - render() { - const email = this.props.email; - if (email == null || email.bodyValues == null) { - return ; - } - let content; - if (this.state.showHTML) { - if (email.htmlBody != null) { - content = ; - } else { - return

No HTML content

; - } - } else { - if (email.textBody != null) { - content = ; - } else { - return

No text content/

; - } - } - return ( - - -
- - - From - - -

- {email.from == null - ? "unknown" - : email.from.map((f) => f.name)} -

- - - Received - - {email.receivedAt} -
-
-
- - - - {content} -
- ); - } - - switchDisplay() { - if (this.state.showHTML) { - this.setState({ - showHTML: false, - }); - } else { - this.setState({ - showHTML: true, - }); - } - } -} -export default EmailContent; diff --git a/src/EmailContentHTML.tsx b/src/EmailContentHTML.tsx deleted file mode 100644 index 3c99379..0000000 --- a/src/EmailContentHTML.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Placeholder from "react-bootstrap/Placeholder"; -import React from "react"; -import Stack from "react-bootstrap/Stack"; - -import { IEmail } from "./client/types"; - -type EmailContentHTMLProps = { - email: IEmail; -}; - -const EmailContentHTML: React.FC = (props) => { - const email = props.email; - if (email.htmlBody == null) { - return ; - } - return ( - - {email.htmlBody.map((h) => - h.partId === undefined ? ( - - ) : ( -
- ), - )} - - ); -}; -export default EmailContentHTML; diff --git a/src/EmailContentText.tsx b/src/EmailContentText.tsx deleted file mode 100644 index ac9ef39..0000000 --- a/src/EmailContentText.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import Placeholder from "react-bootstrap/Placeholder"; -import React from "react"; -import Stack from "react-bootstrap/Stack"; - -import { IEmail } from "./client/types"; - -type EmailContentTextProps = { - email: IEmail; -}; - -const EmailContentText: React.FC = (props) => { - const email = props.email; - if (email.textBody == null) { - return ; - } - return ( - - {email.textBody.map((t) => - t.partId === undefined ? ( -
undefined partId
- ) : ( -
{email.bodyValues![t.partId].value}
- ), - )} -
- ); -}; -export default EmailContentText; diff --git a/src/EmailList.tsx b/src/EmailList.tsx index 2b3d62e..34c44be 100644 --- a/src/EmailList.tsx +++ b/src/EmailList.tsx @@ -3,11 +3,10 @@ import Stack from "react-bootstrap/Stack"; import Client from "./client/Client"; import { IAccount, IMailbox } from "./client/types"; -import EmailSummary from "./EmailSummary"; type EmailListProps = { account: IAccount | null; - client: Client; + client: Client | null; mailbox: IMailbox | null; }; @@ -18,31 +17,37 @@ class EmailList extends React.Component { if (this.props.account == null) return; if (this.props.client == null) return; if (this.props.mailbox == null) return; - this.props.client.ensureEmailList( + this.props.client.emailList( this.props.account.id, this.props.mailbox.id, + [], ); } render() { if ( - this.props.account === null || - this.props.mailbox === null || - this.props.mailbox.emailIds === null + this.props.account == null || + this.props.mailbox == null || + this.props.mailbox.emailIds == null ) { return ; + } else if (this.props.mailbox.emails == null) { + return ( + + {this.props.mailbox.emailIds.map((e) => ( +
+ Email {e} +
+ ))} +
+ ); } else { return ( - - {this.props.mailbox.emailIds.slice(0, 5).map((e) => ( - + + {this.props.mailbox.emails.map((m) => ( +
+ {m.subject} +
))}
); diff --git a/src/EmailSummary.tsx b/src/EmailSummary.tsx deleted file mode 100644 index a9514ea..0000000 --- a/src/EmailSummary.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import Placeholder from "react-bootstrap/Placeholder"; -import React from "react"; - -import Client from "./client/Client"; -import DateTime from "./components/DateTime"; -import { IAccount, IEmailStub, IMailbox } from "./client/types"; - -type EmailSummaryProps = { - account: IAccount; - client: Client; - emailId: string; - emailStub: IEmailStub | null; - mailbox: IMailbox; -}; -type EmailSummaryState = {}; - -class EmailSummary extends React.Component< - EmailSummaryProps, - EmailSummaryState -> { - componentDidMount() { - this.ensureData(); - } - componentDidUpdate() { - this.ensureData(); - } - - ensureData() { - this.props.client.ensureEmailStub( - this.props.account.id, - this.props.emailId, - ); - } - - render() { - const href = - "#" + - this.props.account.id + - "/" + - this.props.mailbox.id + - "/" + - this.props.emailId; - const stub = this.props.emailStub; - if (stub === null) { - return ; - } - return ( - - ); - } -} -export default EmailSummary; diff --git a/src/Mailbox.tsx b/src/Mailbox.tsx index 1213bc5..5a34f51 100644 --- a/src/Mailbox.tsx +++ b/src/Mailbox.tsx @@ -1,19 +1,12 @@ -import React from "react"; - -type MailboxProps = { - accountId: string; - id: string; - name: string; -}; - -const Mailbox: React.FC = ({ accountId, id, name }) => { - const href = "#" + accountId + "/" + id; +import ListGroup from "react-bootstrap/ListGroup"; +function Mailbox() { return ( - - {name} - + + Inbox + Spam + ); -}; +} export default Mailbox; diff --git a/src/MailboxList.tsx b/src/MailboxList.tsx index 3bbe6a6..f42a241 100644 --- a/src/MailboxList.tsx +++ b/src/MailboxList.tsx @@ -1,13 +1,14 @@ import React from "react"; +import Button from "react-bootstrap/Button"; import Stack from "react-bootstrap/Stack"; import Client from "./client/Client"; import { IAccount } from "./client/types"; -import Mailbox from "./Mailbox"; type MailboxListProps = { account: IAccount | null; client: Client | null; + onMailboxSelect: (mailboxId: string) => void; }; type MailboxListState = {}; @@ -19,6 +20,10 @@ class MailboxList extends React.Component { this.props.client.mailboxList(this.props.account.id, []); } + onMailboxClick(id: string) { + this.props.onMailboxSelect(id); + } + render() { return this.props.account == null || this.props.account.mailboxes == null ? ( @@ -26,12 +31,15 @@ class MailboxList extends React.Component { ) : ( {this.props.account.mailboxes.map((m) => ( - + onClick={() => { + this.onMailboxClick(m.id); + }} + > + {m.name} + ))} ); diff --git a/src/client/Client.tsx b/src/client/Client.tsx index 4ed9de5..d002d1c 100644 --- a/src/client/Client.tsx +++ b/src/client/Client.tsx @@ -3,10 +3,10 @@ * None of the dependencies should leak, in types or otherwise */ import * as base64 from "base-64"; -import * as jmapclient from "./jmap-client-ts/src"; -import { FetchTransport } from "./jmap-client-ts/src/utils/fetch-transport"; +import * as jmapclient from "jmap-client-ts"; +import { FetchTransport } from "jmap-client-ts/lib/utils/fetch-transport"; -import { IAccount, IEmail, IEmailStub, IMailbox, ISession } from "./types"; +import { IAccount, IMailbox, ISession } from "./types"; type Callback = () => void; @@ -16,33 +16,31 @@ export interface IAuth { } export interface ClientState { - inFlight: { - emailContents: Set; - emailStubs: Set; - mailboxes: Set; - }; session: ISession | null; } export default class Client { - // All objects which currently are listening for changes - callbacks: Array = []; - jclient: jmapclient.Client | null = null; - state: ClientState = { - inFlight: { - emailContents: new Set(), - emailStubs: new Set(), - mailboxes: new Set(), - }, - session: null, - }; - // Get the currently active account account(accountId: string): IAccount | null { if (!(this.state.session && this.state.session.accounts)) return null; return this.state.session.accounts[accountId]; } + // All objects which currently are listening for changes + callbacks: Array = []; + jclient: jmapclient.Client | null = null; + state: ClientState = { + session: null, + }; + onChange(f: Callback) { + this.callbacks.push(f); + } + + // Ensure that login happens. If this is called many times, only login once. + ensureLogin(auth: IAuth) { + if (this.jclient != null) return; + this.doLogin(auth); + } // Make the request to get system metadata doLogin(auth: IAuth) { const domain = auth.email.split("@")[1]; @@ -67,149 +65,29 @@ export default class Client { return; } - // Ensure we have the full email content - ensureEmailContent(accountId: string, emailId: string) { - if (this.state.session == null) return; - const existing = this.state.session.emails[emailId]; - if (existing != null) return; - this.emailGetContent(accountId, emailId); - } - - // Ensure we have the email summary - ensureEmailStub(accountId: string, emailId: string) { - if (this.state.session == null) return; - const existing = this.state.session.emailStubs[emailId]; - if (existing != null) return; - this.emailGetStub(accountId, emailId); - } - - // Ensure we have the list of emails for the provided account and mailbox - ensureEmailList(accountId: string, mailboxId: string) { - const mailbox = this.mailbox(accountId, mailboxId); - if (mailbox != null && mailbox.emailIds != null) return; - this.emailList(accountId, mailboxId, []); - } - - // Ensure that login happens. If this is called many times, only login once. - ensureLogin(auth: IAuth) { - if (this.jclient != null) return; - this.doLogin(auth); - } - - email(emailId: string): IEmail | null { - if (this.state.session == null) return null; - return this.state.session.emails[emailId]; - } - - emailGetContent(accountId: string, emailId: string) { - if (this.jclient == null) return; - - if (this.state.session == null) return; - if (this.state.inFlight.emailContents.has(emailId)) return; - this.state.inFlight.emailContents.add(emailId); - const msg = "Email get content"; - this.jclient - .email_get({ - accountId: accountId, - ids: [emailId], - fetchAllBodyValues: true, - }) - .then((response) => { - console.log(msg, "response", response); - response.list.forEach((e) => { - const existing = this.state.session!.emails[e.id]; - if (existing !== undefined && existing.subject !== e.subject) { - console.error( - "Expectations violation: email ID is not unique within the server!", - ); - } - this.state.session!.emails[e.id] = { - ...e, - id: e.id, - }; - this._triggerChange(msg + e.id); - }); - }) - .catch((x) => { - console.error("Failed to get email content", emailId, x); - }) - .finally(() => { - this.state.inFlight.emailContents.delete(emailId); - }); - } - - emailGetStub(accountId: string, emailId: string) { - if (this.jclient == null) return; - if (this.state.session == null) return; - if (this.state.inFlight.emailStubs.has(emailId)) return; - this.state.inFlight.emailStubs.add(emailId); - const msg = "Email get summary"; - this.jclient - .email_get({ - accountId: accountId, - ids: [emailId], - properties: ["from", "receivedAt", "subject"], - }) - .then((response) => { - console.log(msg, "response", response); - response.list.forEach((e) => { - if (this.state.session == null) return; - const existing = this.state.session.emailStubs[e.id]; - if (existing !== undefined && existing.subject !== e.subject) { - console.error( - "Expectations violation: email ID is not unique within the server!", - ); - } - this.state.session.emailStubs[e.id] = { - from: e.from, - id: e.id, - receivedAt: e.receivedAt, - subject: e.subject, - }; - this._triggerChange(msg + e.id); - }); - }) - .catch((x) => { - console.error("Failed to get email stub", emailId, x); - }) - .finally(() => { - this.state.inFlight.emailStubs.delete(emailId); - }); - } - emailList(accountId: string, mailboxId: string, ids: Array) { if (this.jclient == null) return; + /*this.jclient.email_get({ + accountId: accountId, + ids: [], + properties: ["threadId"] + });*/ this.jclient .email_query({ accountId: accountId, filter: { inMailbox: mailboxId }, - sort: [ - { - property: "receivedAt", - isAscending: false, - }, - ], }) .then((response) => { const mailbox = this.mailbox(accountId, mailboxId); if (mailbox == null) return; mailbox.emailIds = response.ids; - this._triggerChange("Email list " + mailboxId); + this._triggerChange(); }) - .catch((e) => { - console.error("Failed to get email list from mailbox", mailboxId, e); + .catch(() => { + console.error("OH NOES"); }); } - emailStub(emailId: string): IEmailStub | null { - if (this.state.session == null) return null; - const result = this.state.session.emailStubs[emailId]; - if (result === undefined) { - return null; - } - return result; - } - mailbox(accountId: string, mailboxId: string): IMailbox | null { if (this.state.session == null) return null; const account = this.state.session.accounts[accountId]; @@ -239,19 +117,15 @@ export default class Client { mailboxes.push({ ...m, emailIds: null, + emails: null, }); }); account.mailboxes = mailboxes; - this._triggerChange("Mailboxes " + accountId); + this._triggerChange(); }); } - onChange(f: Callback) { - this.callbacks.push(f); - } - - _triggerChange(msg: string) { - console.log("Client change", msg); + _triggerChange() { this.callbacks.forEach((c) => { c(); }); @@ -271,10 +145,8 @@ export default class Client { { ...account, id: key.toString(), mailboxes: null }, ]), ), - emails: {}, - emailStubs: {}, }; if (!this.state.session) return; - this._triggerChange("Session"); + this._triggerChange(); } } diff --git a/src/client/jmap-client-ts b/src/client/jmap-client-ts deleted file mode 160000 index fdab379..0000000 --- a/src/client/jmap-client-ts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fdab37996a4709b13962b67d1aa49e85a8305755 diff --git a/src/client/types.tsx b/src/client/types.tsx index a479d70..a4a6b3f 100644 --- a/src/client/types.tsx +++ b/src/client/types.tsx @@ -1,18 +1,8 @@ -import * as client from "./jmap-client-ts/src/types"; - -export interface IEmailStub { - from: Array | null; - id: string; - receivedAt: string; - subject: string; -} +import client from "jmap-client-ts/lib/types"; export interface IMailbox extends client.IMailboxProperties { emailIds: Array | null; -} - -export interface IEmail extends client.IEmailProperties { - //sentAt: IutcDate|null, + emails: Array | null; } export interface IAccount extends client.IAccount { @@ -21,11 +11,7 @@ export interface IAccount extends client.IAccount { } export type AccountIdMap = { [accountId: string]: IAccount }; -export type EmailStubIdMap = { [emailId: string]: IEmailStub }; -export type EmailIdMap = { [emailId: string]: IEmail }; export interface ISession extends client.ISession { accounts: AccountIdMap; - emails: EmailIdMap; - emailStubs: EmailStubIdMap; } diff --git a/src/components/DateTime.tsx b/src/components/DateTime.tsx deleted file mode 100644 index 38c2148..0000000 --- a/src/components/DateTime.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from "react"; - -type DateTimeProps = { - d: string; -}; - -const DateTime: React.FC = ({ d }) => { - const datetime = Date.parse(d); - const now = Date.now(); - const diff = (now - datetime) / 1000; - if (diff < 30) return moments ago; - if (diff < 60) return {diff}s; - if (diff < 60 * 60) return {Math.round(diff / 60)}m; - if (diff < 60 * 60 * 48) return {Math.round(diff / (60 * 60))}h; - if (diff < 60 * 60 * 24 * 365) - return {Math.round(diff / (60 * 60 * 24))}d; - return {Math.round(diff / (60 * 60 * 24 * 365))}y; -}; -export default DateTime; diff --git a/src/style.scss b/src/style.scss deleted file mode 100644 index 5de3350..0000000 --- a/src/style.scss +++ /dev/null @@ -1 +0,0 @@ -@import '~bootstrap/scss/bootstrap'; diff --git a/tsconfig.json b/tsconfig.json index 757ec45..9d379a3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,6 +16,5 @@ "noEmit": true, "jsx": "react-jsx" }, - "include": ["src"], - "exclude": ["src/client/jmap-client-ts/tests"] + "include": ["src"] }