diff --git a/src/Journals/JournalMemberAddDialog.tsx b/src/Journals/JournalMemberAddDialog.tsx index c3b3851..c33233a 100644 --- a/src/Journals/JournalMemberAddDialog.tsx +++ b/src/Journals/JournalMemberAddDialog.tsx @@ -12,9 +12,8 @@ import ConfirmationDialog from "../widgets/ConfirmationDialog"; import PrettyFingerprint from "../widgets/PrettyFingerprint"; import * as EteSync from "etesync"; -import { CredentialsData } from "../store"; -import { handleInputChange } from "../helpers"; +import { CredentialsData } from "../store"; interface PropsType { etesync: CredentialsData; @@ -23,127 +22,104 @@ interface PropsType { onClose: () => void; } -class JournalMemberAddDialog extends React.PureComponent { - public state = { - addUser: "", - publicKey: "", - readOnly: false, - userChosen: false, - error: undefined as Error | undefined, - }; - - private handleInputChange: any; - - constructor(props: PropsType) { - super(props); - - this.handleInputChange = handleInputChange(this); - this.onAddRequest = this.onAddRequest.bind(this); - this.onOk = this.onOk.bind(this); - } - - public render() { - const { onClose } = this.props; - const { addUser, userChosen, publicKey, error } = this.state; - - if (error) { - return ( - <> - - User ({addUser}) not found. Have they setup their encryption password from one of the apps? - - - ); - } +export default function JournalMemberAddDialog(props: PropsType) { + const [addUser, setAddUser] = React.useState(""); + const [publicKey, setPublicKey] = React.useState(""); + const [readOnly, setReadOnly] = React.useState(false); + const [userChosen, setUserChosen] = React.useState(false); + const [error, setError] = React.useState(); - if (publicKey) { - return ( - <> - -

- Verify {addUser}'s security fingerprint to ensure the encryption is secure. -

-
- -
-
- - ); - } else { - return ( - <> - - {userChosen ? - - : - <> - - this.setState({ readOnly: event.target.checked })} - /> - } - label="Read only?" - /> - - } - - - ); - } - } - - private onAddRequest(_user: string) { - this.setState({ - userChosen: true, - }); + function onAddRequest(_user: string) { + setUserChosen(true); - const { etesync } = this.props; - const { addUser } = this.state; + const { etesync } = props; const creds = etesync.credentials; const apiBase = etesync.serviceApiUrl; const userInfoManager = new EteSync.UserInfoManager(creds, apiBase); userInfoManager.fetch(addUser).then((userInfo) => { - this.setState({ - publicKey: userInfo.publicKey, - }); + setPublicKey(userInfo.publicKey); }).catch((error) => { - this.setState({ error }); + setError(error); }); } - private onOk() { - const { addUser, publicKey, readOnly } = this.state; - this.props.onOk(addUser, publicKey, readOnly); + function onOk() { + props.onOk(addUser, publicKey, readOnly); } -} -export default JournalMemberAddDialog; + const { onClose } = props; + + if (error) { + return ( + <> + + User ({addUser}) not found. Have they setup their encryption password from one of the apps? + + + ); + } + + if (publicKey) { + return ( + <> + +

+ Verify {addUser}'s security fingerprint to ensure the encryption is secure. +

+
+ +
+
+ + ); + } else { + return ( + <> + + {userChosen ? + + : + <> + setAddUser(ev.target.value)} + /> + setReadOnly(event.target.checked)} + /> + } + label="Read only?" + /> + + } + + + ); + } +} diff --git a/src/Journals/JournalMembers.tsx b/src/Journals/JournalMembers.tsx index 1bd0d32..1e9f045 100644 --- a/src/Journals/JournalMembers.tsx +++ b/src/Journals/JournalMembers.tsx @@ -6,7 +6,6 @@ import sjcl from "sjcl"; import { List, ListItem } from "../widgets/List"; -import { Theme, withTheme } from "@material-ui/core/styles"; import IconMemberAdd from "@material-ui/icons/PersonAdd"; import VisibilityIcon from "@material-ui/icons/Visibility"; @@ -28,140 +27,48 @@ interface PropsType { userInfo: UserInfoData; } -interface PropsTypeInner extends PropsType { - theme: Theme; -} - -class JournalMembers extends React.PureComponent { - public state = { - members: null as EteSync.JournalMemberJson[] | null, - revokeUser: null as string | null, - addMemberOpen: false, - }; - - constructor(props: PropsTypeInner) { - super(props); - - this.onRevokeRequest = this.onRevokeRequest.bind(this); - this.onRevokeDo = this.onRevokeDo.bind(this); - this.onMemberAdd = this.onMemberAdd.bind(this); - } - - public render() { - const { syncJournal } = this.props; - const { members, revokeUser, addMemberOpen } = this.state; +export default function JournalMembers(props: PropsType) { + const [members, setMembers] = React.useState(null); + const [revokeUser, setRevokeUser] = React.useState(null); + const [addMemberOpen, setAddMemberOpen] = React.useState(false); - const info = syncJournal.collection; - const sharingAllowed = syncJournal.journal.version > 1; - - return ( - <> - - - {members ? - - } onClick={() => this.setState({ addMemberOpen: true })}> - Add member - - {(members.length > 0 ? - members.map((member) => ( - this.onRevokeRequest(member.user)} - rightIcon={(member.readOnly) ? () : undefined} - > - {member.user} - - )) - : - - No members - - )} - - : - - } - - this.setState({ revokeUser: null })} - > - Would you like to revoke {revokeUser}'s access?
- Please be advised that a malicious user would potentially be able to retain access to encryption keys. Please refer to the FAQ for more information. -
- - {addMemberOpen && - (sharingAllowed ? - this.setState({ addMemberOpen: false })} - /> - : - this.setState({ addMemberOpen: false })} - onClose={() => this.setState({ addMemberOpen: false })} - > - Sharing of old-style journals is not allowed. In order to share this journal, create a new one, and copy its contents over using the "import" dialog. If you are experiencing any issues, please contact support. - - ) - } - - ); - } - - public componentDidMount() { - this.fetchMembers(); - } - - private fetchMembers() { - const { etesync, syncJournal } = this.props; + function fetchMembers() { + const { etesync, syncJournal } = props; const info = syncJournal.collection; const creds = etesync.credentials; const apiBase = etesync.serviceApiUrl; const journalMembersManager = new EteSync.JournalMembersManager(creds, apiBase, info.uid); journalMembersManager.list().then((members) => { - this.setState({ - members, - }); + setMembers(members); }); } - private onRevokeRequest(user: string) { - this.setState({ - revokeUser: user, - }); + React.useEffect(() => { + fetchMembers(); + }, []); + + function onRevokeRequest(user: string) { + setRevokeUser(user); } - private onRevokeDo() { - const { etesync, syncJournal } = this.props; - const { revokeUser } = this.state; + function onRevokeDo() { + const { etesync, syncJournal } = props; const info = syncJournal.collection; const creds = etesync.credentials; const apiBase = etesync.serviceApiUrl; const journalMembersManager = new EteSync.JournalMembersManager(creds, apiBase, info.uid); journalMembersManager.delete({ user: revokeUser!, key: "" }).then(() => { - this.fetchMembers(); - }); - this.setState({ - revokeUser: null, + fetchMembers(); }); + setRevokeUser(null); } - private onMemberAdd(user: string, publicKey: string, readOnly: boolean) { - const { etesync, syncJournal, userInfo } = this.props; + function onMemberAdd(user: string, publicKey: string, readOnly: boolean) { + const { etesync, syncJournal, userInfo } = props; const journal = syncJournal.journal; - const derived = this.props.etesync.encryptionKey; + const derived = props.etesync.encryptionKey; const keyPair = userInfo.getKeyPair(userInfo.getCryptoManager(derived)); const cryptoManager = journal.getCryptoManager(derived, keyPair); @@ -173,12 +80,76 @@ class JournalMembers extends React.PureComponent { const apiBase = etesync.serviceApiUrl; const journalMembersManager = new EteSync.JournalMembersManager(creds, apiBase, journal.uid); journalMembersManager.create({ user, key: encryptedKey, readOnly }).then(() => { - this.fetchMembers(); - }); - this.setState({ - addMemberOpen: false, + fetchMembers(); }); + setAddMemberOpen(false); } -} -export default withTheme(JournalMembers); + const { syncJournal } = props; + + const info = syncJournal.collection; + const sharingAllowed = syncJournal.journal.version > 1; + + return ( + <> + + + {members ? + + } onClick={() => setAddMemberOpen(true)}> + Add member + + {(members.length > 0 ? + members.map((member) => ( + onRevokeRequest(member.user)} + rightIcon={(member.readOnly) ? () : undefined} + > + {member.user} + + )) + : + + No members + + )} + + : + + } + + setRevokeUser(null)} + > + Would you like to revoke {revokeUser}'s access?
+ Please be advised that a malicious user would potentially be able to retain access to encryption keys. Please refer to the FAQ for more information. +
+ + {addMemberOpen && + (sharingAllowed ? + setAddMemberOpen(false)} + /> + : + setAddMemberOpen(false)} + onClose={() => setAddMemberOpen(false)} + > + Sharing of old-style journals is not allowed. In order to share this journal, create a new one, and copy its contents over using the "import" dialog. If you are experiencing any issues, please contact support. + + ) + } + + ); +}