diff --git a/package-lock.json b/package-lock.json index 260945a..f601b5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10953,6 +10953,11 @@ "safe-buffer": "^5.1.2" } }, + "mdi-material-ui": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/mdi-material-ui/-/mdi-material-ui-5.11.0.tgz", + "integrity": "sha512-9fIvdiKCKAfBoW11LqZsgaxZtu9WCQEd8FL9/8ceLHvStSf+fZM6sC7exwXaXZmzfwtJMfN1KiMGsPBPSTQFQg==" + }, "mdn-data": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", diff --git a/src/App.tsx b/src/App.tsx index 039d081..1457e20 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,6 +19,7 @@ import WelcomePage from './pages/Welcome'; import MessagesPage from './pages/Messages'; import RecommendationsPage from './pages/Recommendations'; import Missingno from './pages/Missingno'; +import You from './pages/You'; import {withSnackbar} from 'notistack'; import {PrivateRoute} from './interfaces/overrides'; import { userLoggedIn } from './utilities/accounts'; @@ -60,6 +61,7 @@ class App extends Component { + diff --git a/src/components/AppLayout/AppLayout.styles.tsx b/src/components/AppLayout/AppLayout.styles.tsx index b9674c8..5cf0c0f 100644 --- a/src/components/AppLayout/AppLayout.styles.tsx +++ b/src/components/AppLayout/AppLayout.styles.tsx @@ -22,7 +22,9 @@ export const styles = (theme: Theme) => createStyles({ backgroundColor: theme.palette.primary.dark, textAlign: 'center', zIndex: 1000, - verticalAlign: 'middle' + verticalAlign: 'middle', + WebkitUserSelect: 'none', + WebkitAppRegion: "drag" }, titleBarText: { color: theme.palette.common.white, @@ -148,5 +150,5 @@ export const styles = (theme: Theme) => createStyles({ bottom: theme.spacing.unit * 2, right: theme.spacing.unit * 2, zIndex: 50 - } + }, }); \ No newline at end of file diff --git a/src/components/AppLayout/AppLayout.tsx b/src/components/AppLayout/AppLayout.tsx index 53c3c6a..02492e4 100644 --- a/src/components/AppLayout/AppLayout.tsx +++ b/src/components/AppLayout/AppLayout.tsx @@ -10,7 +10,7 @@ import PublicIcon from '@material-ui/icons/Public'; import GroupIcon from '@material-ui/icons/Group'; import SettingsIcon from '@material-ui/icons/Settings'; import InfoIcon from '@material-ui/icons/Info'; -import EditIcon from '@material-ui/icons/Edit'; +import CreateIcon from '@material-ui/icons/Create'; //import SupervisedUserCircleIcon from '@material-ui/icons/SupervisedUserCircle'; import ExitToAppIcon from '@material-ui/icons/ExitToApp'; import {styles} from './AppLayout.styles'; @@ -395,7 +395,7 @@ export class AppLayout extends Component { - + diff --git a/src/pages/PageLayout.styles.tsx b/src/pages/PageLayout.styles.tsx index 155005d..73f1783 100644 --- a/src/pages/PageLayout.styles.tsx +++ b/src/pages/PageLayout.styles.tsx @@ -86,8 +86,14 @@ export const styles = (theme: Theme) => createStyles({ paddingLeft: '25%', paddingRight: '25%', }, + position: "relative", zIndex: 1 }, + pageHeroToolbar: { + position: "absolute", + right: theme.spacing.unit * 2, + marginTop: -16, + }, pageListConstraints: { paddingLeft: theme.spacing.unit, paddingRight: theme.spacing.unit, @@ -179,4 +185,26 @@ export const styles = (theme: Theme) => createStyles({ color: theme.palette.primary.light } }, + youHeadingAvatar: { + height: 88, + width: 88 + }, + youPaper: { + padding: theme.spacing.unit * 2, + }, + youGrid: { + textAlign: "center", + '& *': { + marginLeft: "auto", + marginRight: "auto", + } + }, + youGridAvatar: { + height: 128, + width: 128 + }, + youGridImage: { + width: 'auto', + height: 128 + }, }); \ No newline at end of file diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx index 11c1272..ed25744 100644 --- a/src/pages/ProfilePage.tsx +++ b/src/pages/ProfilePage.tsx @@ -7,9 +7,11 @@ import { Status } from '../types/Status'; import { Relationship } from '../types/Relationship'; import Post from '../components/Post'; import {withSnackbar} from 'notistack'; -import { LinkableButton } from '../interfaces/overrides'; +import { LinkableButton, LinkableIconButton } from '../interfaces/overrides'; import { emojifyString } from '../utilities/emojis'; +import AccountEditIcon from 'mdi-material-ui/AccountEdit'; + interface IProfilePageState { account?: Account; relationship?: Relationship; @@ -89,6 +91,14 @@ class ProfilePage extends Component { this.getAccountData(params.profileId); } + isItMe(): boolean { + if (this.state.account) { + return this.state.account.id === JSON.parse(localStorage.getItem('account') as string).id; + } else { + return false; + } + } + getRelationships() { this.client.get("/accounts/relationships", {id: this.props.match.params.profileId }).then((resp: any) => { let relationship: Relationship = resp.data[0]; @@ -216,6 +226,14 @@ class ProfilePage extends Component {
+ { + this.isItMe()? + + + + + : null + } {this.state.account ? '@' + this.state.account.acct: ""} diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index 1942d26..d80606f 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -30,6 +30,7 @@ import {themes, defaultTheme} from '../types/HyperspaceTheme'; import ThemePreview from '../components/ThemePreview'; import {setHyperspaceTheme, getHyperspaceTheme} from '../utilities/themes'; import { Visibility } from '../types/Visibility'; +import {LinkableButton} from '../interfaces/overrides'; import OpenInNewIcon from '@material-ui/icons/OpenInNew'; import DevicesIcon from '@material-ui/icons/Devices'; @@ -351,13 +352,19 @@ class SettingsPage extends Component {
- Accounts + Your Account + + + Edit + + + diff --git a/src/pages/You.tsx b/src/pages/You.tsx new file mode 100644 index 0000000..12bb6d7 --- /dev/null +++ b/src/pages/You.tsx @@ -0,0 +1,192 @@ +import React, {Component} from 'react'; +import {withStyles, Typography, Paper, Avatar, Button, TextField, ListItem, ListItemText, ListItemAvatar, List, Grid} from '@material-ui/core'; +import {withSnackbar, withSnackbarProps} from 'notistack'; +import {styles} from './PageLayout.styles'; +import { Account } from '../types/Account'; +import Mastodon from 'megalodon'; +import filedialog from 'file-dialog'; + +import PersonIcon from '@material-ui/icons/Person'; + +interface IYouProps extends withSnackbarProps { + classes: any; +} + +interface IYouState { + currentAccount: Account; + newDisplayName?: string; + newBio?: string; +} + +class You extends Component { + + client: Mastodon; + + constructor(props: any) { + super(props); + + this.client = new Mastodon(localStorage.getItem('access_token') as string, localStorage.getItem('baseurl') as string + "/api/v1"); + + this.state = { + currentAccount: this.getAccount() + } + } + + getAccount() { + let acct = localStorage.getItem('account'); + if (acct) { + return JSON.parse(acct); + } + } + + updateAvatar() { + filedialog({ + multiple: false, + accept: "image/*" + }).then((images: FileList) => { + if (images.length > 0) { + this.props.enqueueSnackbar("Updating avatar...", { persist: true, key: "persistAvatar" }); + let upload = new FormData(); + upload.append("avatar", images[0]); + this.client.patch("/accounts/update_credentials", upload).then((acct: any) => { + let currentAccount: Account = acct.data; + this.setState({ currentAccount }); + localStorage.setItem("account", JSON.stringify(currentAccount)); + this.props.closeSnackbar("persistAvatar"); + this.props.enqueueSnackbar("Avatar updated successfully."); + }).catch((err: Error) => { + this.props.closeSnackbar("persistAvatar"); + this.props.enqueueSnackbar("Couldn't update avatar: " + err.name, { variant: "error" }); + }) + } + }).catch((err: Error) => { + this.props.enqueueSnackbar("Couldn't update avatar: " + err.name); + }) + } + + updateHeader() { + filedialog({ + multiple: false, + accept: "image/*" + }).then((images: FileList) => { + if (images.length > 0) { + this.props.enqueueSnackbar("Updating header...", { persist: true, key: "persistHeader" }); + let upload = new FormData(); + upload.append("header", images[0]); + this.client.patch("/accounts/update_credentials", upload).then((acct: any) => { + let currentAccount: Account = acct.data; + this.setState({ currentAccount }); + localStorage.setItem("account", JSON.stringify(currentAccount)); + this.props.closeSnackbar("persistHeader"); + this.props.enqueueSnackbar("Header updated successfully."); + }).catch((err: Error) => { + this.props.closeSnackbar("persistHeader"); + this.props.enqueueSnackbar("Couldn't update header: " + err.name, { variant: "error" }); + }) + } + }).catch((err: Error) => { + this.props.enqueueSnackbar("Couldn't update header: " + err.name); + }) + } + + removeHTMLContent(text: string) { + const div = document.createElement('div'); + div.innerHTML = text; + let innerContent = div.textContent || div.innerText || ""; + return innerContent; + } + changeDisplayName() { + this.client.patch('/accounts/update_credentials', { + display_name: this.state.newDisplayName? this.state.newDisplayName: this.state.currentAccount.display_name + }) + .then((acct: any) =>{ + let currentAccount: Account = acct.data + this.setState({currentAccount}); + localStorage.setItem('account', JSON.stringify(currentAccount)); + this.props.closeSnackbar("persistHeader"); + this.props.enqueueSnackbar("Display name updated to " + this.state.newDisplayName); + } ).catch((err:Error) => { + console.error(err.name) + this.props.closeSnackbar("persistHeader"); + this.props.enqueueSnackbar("Couldn't update display name: " + err.name, { variant: "error" }) + }) + } + + updateDisplayname(name: string) { + this.setState({ newDisplayName: name }); + }; + changeBio() { + this.client.patch('/accounts/update_credentials', {note: this.state.newBio? this.state.newBio: this.state.currentAccount.note}) + .then((acct:any) => { + let currentAccount: Account = acct.data + this.setState({currentAccount}); + localStorage.setItem('account', JSON.stringify(currentAccount)); + this.props.closeSnackbar("persistHeader"); + this.props.enqueueSnackbar("Bio updated successfully."); + }).catch((err: Error) => { + console.error(err.name) + this.props.closeSnackbar("persistHeader"); + this.props.enqueueSnackbar("Couldn't update bio: " + err.name, { variant: "error"}); + }) + } + + updateBio(bio:string){ + this.setState({newBio:bio}) + } + + render() { + const {classes} = this.props; + return ( +
+
+
+
+ + Edit your profile +
+
+ + +
+
+
+
+
+ + Display Name +
+ this.updateDisplayname(event.target.value)}> + +
+ +
+
+
+ + About you +
+ this.updateBio(event.target.value)}> + +
+ +
+
+
+
+ ); + } +} + +export default withStyles(styles)(withSnackbar(You)); \ No newline at end of file