Fix areas where localStorage couldn't be read

Signed-off-by: Marquis Kurt <software@marquiskurt.net>
This commit is contained in:
Marquis Kurt 2019-10-03 13:03:42 -04:00
parent e75a964a39
commit 0d4ec15e44
No known key found for this signature in database
GPG Key ID: 725636D259F5402D
6 changed files with 317 additions and 203 deletions

View File

@ -1,6 +1,6 @@
{
"version": "1.0.0beta7",
"location": "desktop",
"location": "https://localhost:3000",
"branding": {
"name": "Hyperspace",
"logo": "logo.svg",

View File

@ -42,7 +42,7 @@ 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";
import { UAccount } from "../../types/Account";
import { MultiAccount, UAccount } from "../../types/Account";
import {
LinkableListItem,
LinkableIconButton,
@ -55,7 +55,10 @@ import { withSnackbar } from "notistack";
import { getConfig, getUserDefaultBool } from "../../utilities/settings";
import { isDesktopApp, isDarwinApp } from "../../utilities/desktop";
import { Config } from "../../types/Config";
import { getAccountRegistry } from "../../utilities/accounts";
import {
getAccountRegistry,
removeAccountFromRegistry
} from "../../utilities/accounts";
interface IAppLayoutState {
acctMenuOpen: boolean;
@ -228,10 +231,22 @@ export class AppLayout extends Component<any, IAppLayoutState> {
logOutAndRestart() {
let loginData = localStorage.getItem("login");
if (loginData) {
let registry = getAccountRegistry();
registry.forEach((registryItem: MultiAccount, index: number) => {
if (
registryItem.access_token ===
localStorage.getItem("access_token")
) {
removeAccountFromRegistry(index);
}
});
let items = ["login", "account", "baseurl", "access_token"];
items.forEach(entry => {
localStorage.removeItem(entry);
});
window.location.reload();
}
}
@ -631,48 +646,7 @@ export class AppLayout extends Component<any, IAppLayoutState> {
</Hidden>
</nav>
</div>
<Dialog
open={this.state.logOutOpen}
onClose={() => this.toggleLogOutDialog()}
>
<DialogTitle id="alert-dialog-title">
Log out of{" "}
{this.state.brandName
? this.state.brandName
: "Hyperspace"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
You'll need to remove{" "}
{this.state.brandName
? this.state.brandName
: "Hyperspace"}{" "}
from your list of authorized apps and log in again
if you want to use{" "}
{this.state.brandName
? this.state.brandName
: "Hyperspace"}
.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => this.toggleLogOutDialog()}
color="primary"
autoFocus
>
Cancel
</Button>
<Button
onClick={() => {
this.logOutAndRestart();
}}
color="primary"
>
Log out
</Button>
</DialogActions>
</Dialog>
{this.logoutDialog()}
<Tooltip title="Create a new post">
<LinkableFab
to="/compose"
@ -686,6 +660,57 @@ export class AppLayout extends Component<any, IAppLayoutState> {
</div>
);
}
logoutDialog() {
return (
<Dialog
open={this.state.logOutOpen}
onClose={() => this.toggleLogOutDialog()}
>
<DialogTitle id="alert-dialog-title">
Log out of{" "}
{this.state.brandName ? this.state.brandName : "Hyperspace"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
<Typography paragraph>
You'll need to remove{" "}
{this.state.brandName
? this.state.brandName
: "Hyperspace"}{" "}
from your list of authorized apps and log in again
if you want to use{" "}
{this.state.brandName
? this.state.brandName
: "Hyperspace"}
.
</Typography>
<Typography paragraph>
Logging out will also remove this account from the
account list.
</Typography>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => this.toggleLogOutDialog()}
color="primary"
autoFocus
>
Cancel
</Button>
<Button
onClick={() => {
this.logOutAndRestart();
}}
color="primary"
>
Log out
</Button>
</DialogActions>
</Dialog>
);
}
}
export default withStyles(styles)(withSnackbar(AppLayout));

View File

@ -1,33 +1,32 @@
import React from "react";
import {
Typography,
IconButton,
Card,
CardHeader,
Avatar,
CardContent,
CardActions,
withStyles,
Menu,
MenuItem,
Chip,
Divider,
CardMedia,
CardActionArea,
ExpansionPanel,
ExpansionPanelSummary,
ExpansionPanelDetails,
Zoom,
Tooltip,
RadioGroup,
Radio,
FormControlLabel,
Button,
Card,
CardActionArea,
CardActions,
CardContent,
CardHeader,
CardMedia,
Dialog,
DialogTitle,
DialogActions,
DialogContent,
DialogContentText,
DialogActions
DialogTitle,
Divider,
ExpansionPanel,
ExpansionPanelDetails,
ExpansionPanelSummary,
FormControlLabel,
IconButton,
Menu,
MenuItem,
Radio,
RadioGroup,
Tooltip,
Typography,
withStyles,
Zoom
} from "@material-ui/core";
import MoreVertIcon from "@material-ui/icons/MoreVert";
import ReplyIcon from "@material-ui/icons/Reply";
@ -51,10 +50,10 @@ import moment from "moment";
import AttachmentComponent from "../Attachment";
import Mastodon from "megalodon";
import {
LinkableAvatar,
LinkableChip,
LinkableMenuItem,
LinkableIconButton,
LinkableAvatar
LinkableMenuItem
} from "../../interfaces/overrides";
import { withSnackbar } from "notistack";
import ShareMenu from "./PostShareMenu";
@ -73,6 +72,7 @@ interface IPostState {
menuIsOpen: boolean;
myVote?: [number];
deletePostDialog: boolean;
myAccount?: Account;
}
export class Post extends React.Component<any, IPostState> {
@ -94,6 +94,25 @@ export class Post extends React.Component<any, IPostState> {
this.client = this.props.client;
}
componentWillMount() {
this.client
.get("/accounts/verify_credentials")
.then((resp: any) => {
let account: Account = resp.data;
this.setState({
myAccount: account
});
})
.catch((err: Error) => {
console.error(err);
this.setState({
myAccount: JSON.parse(localStorage.getItem(
"account"
) as string)
});
});
}
togglePostMenu() {
this.setState({ menuIsOpen: !this.state.menuIsOpen });
}
@ -105,7 +124,7 @@ export class Post extends React.Component<any, IPostState> {
deletePost() {
this.client
.del("/statuses/" + this.state.post.id)
.then((resp: any) => {
.then(() => {
this.props.enqueueSnackbar(
"Post deleted. Refresh to see changes."
);
@ -261,7 +280,7 @@ export class Post extends React.Component<any, IPostState> {
<RadioGroup value={this.findBiggestVote()}>
{status.poll.options.map(
(pollOption: PollOption) => {
let x = (
return (
<FormControlLabel
disabled
value={pollOption.title}
@ -273,7 +292,6 @@ export class Post extends React.Component<any, IPostState> {
}
/>
);
return x;
}
)}
</RadioGroup>
@ -302,7 +320,7 @@ export class Post extends React.Component<any, IPostState> {
>
{status.poll.options.map(
(pollOption: PollOption) => {
let x = (
return (
<FormControlLabel
value={pollOption.title}
control={<Radio />}
@ -313,13 +331,12 @@ export class Post extends React.Component<any, IPostState> {
}
/>
);
return x;
}
)}
</RadioGroup>
<Button
color="primary"
onClick={(event: any) => this.submitVote()}
onClick={() => this.submitVote()}
>
Vote
</Button>
@ -380,7 +397,6 @@ export class Post extends React.Component<any, IPostState> {
}
getReblogOfPost(of: Status | null) {
const { classes } = this.props;
if (of !== null) {
return of.sensitive
? this.getSensitiveContent(of.spoiler_text, of)
@ -653,7 +669,7 @@ export class Post extends React.Component<any, IPostState> {
dangerouslySetInnerHTML={{
__html: this.getReblogAuthors(post)
}}
></Typography>
/>
}
subheader={moment(post.created_at).format(
"MMMM Do YYYY [at] h:mm A"
@ -827,9 +843,8 @@ export class Post extends React.Component<any, IPostState> {
Open in Web
</MenuItem>
</div>
{post.account.id ==
JSON.parse(localStorage.getItem("account") as string)
.id ? (
{this.state.myAccount &&
post.account.id == this.state.myAccount.id ? (
<div>
<Divider />
<MenuItem

View File

@ -22,6 +22,12 @@ if (userLoggedIn()) {
refreshUserAccountData();
}
window.onstorage = (event: any) => {
if (event.key == "account") {
window.location.reload();
}
};
ReactDOM.render(
<HashRouter>
<SnackbarProvider

View File

@ -1,16 +1,12 @@
import React, { Component } from "react";
import {
withStyles,
Typography,
Paper,
Avatar,
Button,
CircularProgress,
Paper,
TextField,
ListItem,
ListItemText,
ListItemAvatar,
List,
Grid
Typography,
withStyles
} from "@material-ui/core";
import { withSnackbar, withSnackbarProps } from "notistack";
import { styles } from "./PageLayout.styles";
@ -18,16 +14,17 @@ 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;
currentAccount?: Account;
newDisplayName?: string;
newBio?: string;
viewIsLoading: boolean;
viewLoaded: boolean;
viewErrored: boolean;
}
class You extends Component<IYouProps, IYouState> {
@ -42,12 +39,42 @@ class You extends Component<IYouProps, IYouState> {
);
this.state = {
currentAccount: this.getAccount()
viewIsLoading: true,
viewLoaded: false,
viewErrored: false
};
}
componentWillMount() {
this.client
.get("/accounts/verify_credentials")
.then((resp: any) => {
let currentAccount: Account = resp.data;
this.setState({
currentAccount,
viewIsLoading: false,
viewLoaded: true
});
})
.catch(() => {
if (this.getAccount()) {
this.setState({
currentAccount: this.getAccount(),
viewIsLoading: false,
viewLoaded: true
});
} else {
this.setState({
viewIsLoading: false,
viewErrored: true
});
}
});
}
getAccount() {
let acct = localStorage.getItem("account");
console.log(acct);
if (acct) {
return JSON.parse(acct);
}
@ -142,15 +169,16 @@ class You extends Component<IYouProps, IYouState> {
removeHTMLContent(text: string) {
const div = document.createElement("div");
div.innerHTML = text;
let innerContent = div.textContent || div.innerText || "";
return innerContent;
return div.textContent || div.innerText || "";
}
changeDisplayName() {
this.client
.patch("/accounts/update_credentials", {
display_name: this.state.newDisplayName
? this.state.newDisplayName
: this.state.currentAccount.display_name
: this.state.currentAccount
? this.state.currentAccount.display_name
: ""
})
.then((acct: any) => {
let currentAccount: Account = acct.data;
@ -179,7 +207,9 @@ class You extends Component<IYouProps, IYouState> {
.patch("/accounts/update_credentials", {
note: this.state.newBio
? this.state.newBio
: this.state.currentAccount.note
: this.state.currentAccount
? this.state.currentAccount.note
: ""
})
.then((acct: any) => {
let currentAccount: Account = acct.data;
@ -205,116 +235,155 @@ class You extends Component<IYouProps, IYouState> {
const { classes } = this.props;
return (
<div className={classes.pageLayoutMinimalConstraints}>
<div className={classes.pageHeroBackground}>
<div
className={classes.pageHeroBackgroundImage}
style={{
backgroundImage: `url("${this.state.currentAccount.header_static}")`
}}
/>
<div className={classes.profileContent}>
<br />
<Avatar
className={classes.profileAvatar}
src={this.state.currentAccount.avatar_static}
/>
<div
className={classes.profileUserBox}
style={{ paddingTop: 8, paddingBottom: 8 }}
>
<Typography
variant="h4"
color="inherit"
component="h1"
>
Edit your profile
</Typography>
<Typography color="inherit">
Change information such as your display name,
bio, and images used here.
</Typography>
<div>
<Button
className={classes.pageProfileFollowButton}
variant="contained"
onClick={() => this.updateAvatar()}
{this.state.viewErrored ? (
<Paper className={classes.errorCard}>
<Typography variant="h4">Bummer.</Typography>
<Typography variant="h6">
Something went wrong when trying to get your account
information.
</Typography>
</Paper>
) : (
<span />
)}
{this.state.currentAccount ? (
<div>
<div className={classes.pageHeroBackground}>
<div
className={classes.pageHeroBackgroundImage}
style={{
backgroundImage: `url("${this.state.currentAccount.header_static}")`
}}
/>
<div className={classes.profileContent}>
<br />
<Avatar
className={classes.profileAvatar}
src={
this.state.currentAccount.avatar_static
}
/>
<div
className={classes.profileUserBox}
style={{ paddingTop: 8, paddingBottom: 8 }}
>
Change Avatar
</Button>
<Button
className={classes.pageProfileFollowButton}
variant="contained"
onClick={() => this.updateHeader()}
>
Change Header
</Button>
<Typography
variant="h4"
color="inherit"
component="h1"
>
Edit your profile
</Typography>
<Typography color="inherit">
Change information such as your display
name, bio, and images used here.
</Typography>
<div>
<Button
className={
classes.pageProfileFollowButton
}
variant="contained"
onClick={() => this.updateAvatar()}
>
Change Avatar
</Button>
<Button
className={
classes.pageProfileFollowButton
}
variant="contained"
onClick={() => this.updateHeader()}
>
Change Header
</Button>
</div>
</div>
</div>
</div>
<div className={classes.pageContentLayoutConstraints}>
<Paper className={classes.youPaper}>
<Typography variant="h5" component="h2">
Display Name
</Typography>
<br />
<TextField
className={classes.TextField}
defaultValue={
this.state.currentAccount.display_name
}
rowsMax="1"
variant="outlined"
fullWidth
onChange={(event: any) =>
this.updateDisplayName(
event.target.value
)
}
/>
<div style={{ textAlign: "right" }}>
<Button
className={
classes.pageProfileFollowButton
}
color="primary"
onClick={() => this.changeDisplayName()}
>
Update display Name
</Button>
</div>
</Paper>
<br />
<Paper className={classes.youPaper}>
<Typography variant="h5" component="h2">
About you
</Typography>
<br />
<TextField
className={classes.TextField}
defaultValue={
this.state.currentAccount.note
? this.removeHTMLContent(
this.state.currentAccount.note
)
: "Tell a little bit about yourself"
}
multiline
variant="outlined"
rows="2"
rowsMax="5"
fullWidth
onChange={(event: any) =>
this.updateBio(event.target.value)
}
/>
<div style={{ textAlign: "right" }}>
<Button
className={
classes.pageProfileFollowButton
}
color="primary"
onClick={() => this.changeBio()}
>
Update biography
</Button>
</div>
</Paper>
</div>
</div>
</div>
<div className={classes.pageContentLayoutConstraints}>
<Paper className={classes.youPaper}>
<Typography variant="h5" component="h2">
Display Name
</Typography>
<br />
<TextField
className={classes.TextField}
defaultValue={
this.state.currentAccount.display_name
}
rowsMax="1"
variant="outlined"
fullWidth
onChange={(event: any) =>
this.updateDisplayName(event.target.value)
}
) : (
"AAA"
)}
{this.state.viewIsLoading ? (
<div style={{ textAlign: "center" }}>
<CircularProgress
className={classes.progress}
color="primary"
/>
<div style={{ textAlign: "right" }}>
<Button
className={classes.pageProfileFollowButton}
color="primary"
onClick={() => this.changeDisplayName()}
>
Update display Name
</Button>
</div>
</Paper>
<br />
<Paper className={classes.youPaper}>
<Typography variant="h5" component="h2">
About you
</Typography>
<br />
<TextField
className={classes.TextField}
defaultValue={
this.state.currentAccount.note
? this.removeHTMLContent(
this.state.currentAccount.note
)
: "Tell a little bit about yourself"
}
multiline
variant="outlined"
rows="2"
rowsMax="5"
fullWidth
onChange={(event: any) =>
this.updateBio(event.target.value)
}
/>
<div style={{ textAlign: "right" }}>
<Button
className={classes.pageProfileFollowButton}
color="primary"
onClick={() => this.changeBio()}
>
Update biography
</Button>
</div>
</Paper>
</div>
</div>
) : (
<span />
)}
</div>
);
}

View File

@ -71,7 +71,6 @@ export function addAccountToRegistry(
access_token: string,
username: string
) {
console.log("Firing!");
const newAccount: MultiAccount = {
host: base_url,
username,