mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-23 17:12:53 +03:00
reworked profile public files
This commit is contained in:
parent
dcd0f844eb
commit
e4124f28d1
@ -176,7 +176,7 @@ export const bytesToSize = (bytes, decimals = 2) => {
|
|||||||
|
|
||||||
const k = 1024;
|
const k = 1024;
|
||||||
const dm = decimals < 0 ? 0 : decimals;
|
const dm = decimals < 0 ? 0 : decimals;
|
||||||
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||||
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
|
||||||
|
@ -10,8 +10,13 @@ import * as Events from "~/common/custom-events";
|
|||||||
|
|
||||||
import Cookies from "universal-cookie";
|
import Cookies from "universal-cookie";
|
||||||
import JSZip from "jszip";
|
import JSZip from "jszip";
|
||||||
|
|
||||||
import { saveAs } from "file-saver";
|
import { saveAs } from "file-saver";
|
||||||
|
|
||||||
|
//NOTE(martina): this file is for utility *API-calling* functions
|
||||||
|
//For non API related utility functions, see common/utilities.js
|
||||||
|
//And for uploading related utility functions, see common/file-utilities.js
|
||||||
|
|
||||||
const cookies = new Cookies();
|
const cookies = new Cookies();
|
||||||
|
|
||||||
export const authenticate = async (state) => {
|
export const authenticate = async (state) => {
|
||||||
|
24
common/utilities.js
Normal file
24
common/utilities.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//NOTE(martina): this file is for utility functions that do not involve API calls
|
||||||
|
//For API related utility functions, see common/user-behaviors.js
|
||||||
|
//And for uploading related utility functions, see common/file-utilities.js
|
||||||
|
|
||||||
|
export const getPublicAndPrivateFiles = ({ viewer }) => {
|
||||||
|
let publicFileIds = [];
|
||||||
|
for (let slate of viewer.slates) {
|
||||||
|
if (slate.data.public) {
|
||||||
|
publicFileIds.push(...slate.data.objects.map((obj) => obj.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let publicFiles = [];
|
||||||
|
let privateFiles = [];
|
||||||
|
let library = viewer.library[0]?.children || [];
|
||||||
|
for (let file of library) {
|
||||||
|
if (file.public || publicFileIds.includes(file.id)) {
|
||||||
|
publicFiles.push(file);
|
||||||
|
} else {
|
||||||
|
privateFiles.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { publicFiles, privateFiles };
|
||||||
|
};
|
@ -489,7 +489,7 @@ export default class CarouselSidebarData extends React.Component {
|
|||||||
<div css={STYLES_ACTION} onClick={() => this._handleCopy(url, "gatewayUrlCopying")}>
|
<div css={STYLES_ACTION} onClick={() => this._handleCopy(url, "gatewayUrlCopying")}>
|
||||||
<SVG.Data height="24px" />
|
<SVG.Data height="24px" />
|
||||||
<span style={{ marginLeft: 16 }}>
|
<span style={{ marginLeft: 16 }}>
|
||||||
{this.state.loading === "gatewayUrlCopying" ? "Copied!" : "Copy external URL"}
|
{this.state.loading === "gatewayUrlCopying" ? "Copied!" : "Copy file URL"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div css={STYLES_ACTION} onClick={this._handleDownload}>
|
<div css={STYLES_ACTION} onClick={this._handleDownload}>
|
||||||
|
@ -3,6 +3,7 @@ import * as Constants from "~/common/constants";
|
|||||||
import * as Strings from "~/common/strings";
|
import * as Strings from "~/common/strings";
|
||||||
import * as SVG from "~/common/svg";
|
import * as SVG from "~/common/svg";
|
||||||
import * as Actions from "~/common/actions";
|
import * as Actions from "~/common/actions";
|
||||||
|
import * as Utilities from "~/common/utilities";
|
||||||
|
|
||||||
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
|
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
|
||||||
import { css } from "@emotion/react";
|
import { css } from "@emotion/react";
|
||||||
@ -235,19 +236,15 @@ function UserEntry({ user, button, onClick, message, external, url }) {
|
|||||||
|
|
||||||
export default class Profile extends React.Component {
|
export default class Profile extends React.Component {
|
||||||
_ref = null;
|
_ref = null;
|
||||||
lastLength = null;
|
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
tab: 1,
|
tab: 1,
|
||||||
view: 0,
|
view: 0,
|
||||||
fileTab: 0,
|
|
||||||
slateTab: 0,
|
slateTab: 0,
|
||||||
peerTab: 0,
|
peerTab: 0,
|
||||||
copyValue: "",
|
copyValue: "",
|
||||||
contextMenu: null,
|
contextMenu: null,
|
||||||
publicSlates: [],
|
|
||||||
publicFiles: [],
|
publicFiles: [],
|
||||||
pseudoPrivateFiles: [],
|
|
||||||
isFollowing: this.props.external
|
isFollowing: this.props.external
|
||||||
? false
|
? false
|
||||||
: !!this.props.viewer.subscriptions.filter((entry) => {
|
: !!this.props.viewer.subscriptions.filter((entry) => {
|
||||||
@ -255,70 +252,19 @@ export default class Profile extends React.Component {
|
|||||||
}).length,
|
}).length,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount = async () => {
|
componentDidMount = () => {
|
||||||
await this.filterByVisibility();
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidUpdate = async (prevProps) => {
|
|
||||||
if (this.props.creator?.id !== prevProps.creator?.id) {
|
|
||||||
this.setState({
|
|
||||||
tab: 1,
|
|
||||||
view: 0,
|
|
||||||
fileTab: 0,
|
|
||||||
slateTab: 0,
|
|
||||||
peerTab: 0,
|
|
||||||
isFollowing: this.props.external
|
|
||||||
? false
|
|
||||||
: !!this.props.viewer.subscriptions.filter((entry) => {
|
|
||||||
return entry.target_user_id === this.props.creator.id;
|
|
||||||
}).length,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.lastLength != null &&
|
|
||||||
this.props.creator?.library[0].children.length !== this.lastLength
|
|
||||||
) {
|
|
||||||
this.filterByVisibility();
|
this.filterByVisibility();
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
filterByVisibility = async () => {
|
filterByVisibility = () => {
|
||||||
let publicFiles = [];
|
let publicFiles = [];
|
||||||
let pseudoPrivateFiles = [];
|
if (this.props.isOwner) {
|
||||||
let files = this.props.creator.library[0].children;
|
const res = Utilities.getPublicAndPrivateFiles({ viewer: this.props.creator });
|
||||||
let publicSlates =
|
publicFiles = res.publicFiles;
|
||||||
this.props.creator.username === this.props.viewer?.username
|
|
||||||
? this.props.creator.slates.filter((slate) => {
|
|
||||||
return slate.data.public === true;
|
|
||||||
})
|
|
||||||
: this.props.creator.slates;
|
|
||||||
|
|
||||||
let publicSlateFiles = publicSlates
|
|
||||||
.reduce((acc, curr) => {
|
|
||||||
return acc.concat(curr.data.objects);
|
|
||||||
}, [])
|
|
||||||
.reduce((acc, curr) => {
|
|
||||||
return acc.concat(curr.cid);
|
|
||||||
}, [])
|
|
||||||
.reduce((acc, curr) => {
|
|
||||||
if (acc.indexOf(curr) === -1) {
|
|
||||||
acc.push(curr);
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, []);
|
|
||||||
for (let file of files) {
|
|
||||||
if (file.public === true || publicSlateFiles.indexOf(file.cid) != -1) {
|
|
||||||
publicFiles.push(file);
|
|
||||||
} else {
|
} else {
|
||||||
pseudoPrivateFiles.push(file);
|
publicFiles = this.props.creator.library[0].children;
|
||||||
}
|
}
|
||||||
}
|
this.setState({ publicFiles: publicFiles });
|
||||||
this.setState({
|
|
||||||
publicSlates: publicSlates,
|
|
||||||
publicFiles: publicFiles,
|
|
||||||
pseudoPrivateFiles: pseudoPrivateFiles,
|
|
||||||
});
|
|
||||||
this.lastLength = this.props.creator?.library[0].children.length;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleCopy = (e, value) => {
|
_handleCopy = (e, value) => {
|
||||||
@ -352,34 +298,32 @@ export default class Profile extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let isOwner = this.props.creator.username === this.props.viewer?.username;
|
let isOwner = this.props.isOwner;
|
||||||
let creator = this.props.creator;
|
let creator = this.props.creator;
|
||||||
|
let username = this.state.slateTab === 0 ? creator.username : null;
|
||||||
let subscriptions = this.props.creator.subscriptions || [];
|
let subscriptions = this.props.creator.subscriptions || [];
|
||||||
let subscribers = this.props.creator.subscribers || [];
|
let subscribers = this.props.creator.subscribers || [];
|
||||||
let dataItems = !isOwner
|
|
||||||
? this.state.publicFiles
|
|
||||||
: this.state.fileTab === 0
|
|
||||||
? this.props.creator.library[0].children
|
|
||||||
: this.state.fileTab === 1
|
|
||||||
? this.state.publicFiles
|
|
||||||
: this.state.pseudoPrivateFiles;
|
|
||||||
let exploreSlates = this.props.exploreSlates;
|
let exploreSlates = this.props.exploreSlates;
|
||||||
|
|
||||||
let followingSlates = subscriptions
|
let slates = [];
|
||||||
|
if (this.state.tab === 1) {
|
||||||
|
if (this.state.slateTab === 0) {
|
||||||
|
slates = isOwner
|
||||||
|
? creator.slates.filter((slate) => slate.data.public === true)
|
||||||
|
: creator.slates;
|
||||||
|
} else {
|
||||||
|
slates = subscriptions
|
||||||
.filter((relation) => {
|
.filter((relation) => {
|
||||||
return !!relation.target_slate_id;
|
return !!relation.target_slate_id;
|
||||||
})
|
})
|
||||||
.map((relation) => relation.slate);
|
.map((relation) => relation.slate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let slates =
|
let peers = [];
|
||||||
this.state.slateTab === 0
|
if (this.state.tab === 2) {
|
||||||
? this.state.publicSlates
|
if (this.state.peerTab === 0) {
|
||||||
: followingSlates?.length
|
peers = subscriptions
|
||||||
? followingSlates
|
|
||||||
: null;
|
|
||||||
let username = this.state.slateTab === 0 ? creator.username : null;
|
|
||||||
|
|
||||||
let following = subscriptions
|
|
||||||
.filter((relation) => {
|
.filter((relation) => {
|
||||||
return !!relation.target_user_id;
|
return !!relation.target_user_id;
|
||||||
})
|
})
|
||||||
@ -455,8 +399,8 @@ export default class Profile extends React.Component {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
let followers = subscribers.map((relation) => {
|
peers = subscribers.map((relation) => {
|
||||||
let button = (
|
let button = (
|
||||||
<div css={STYLES_ITEM_BOX} onClick={(e) => this._handleClick(e, relation.id)}>
|
<div css={STYLES_ITEM_BOX} onClick={(e) => this._handleClick(e, relation.id)}>
|
||||||
<SVG.MoreHorizontal height="24px" />
|
<SVG.MoreHorizontal height="24px" />
|
||||||
@ -528,6 +472,8 @@ export default class Profile extends React.Component {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let total = creator.slates.reduce((total, slate) => {
|
let total = creator.slates.reduce((total, slate) => {
|
||||||
return total + slate.data?.objects?.length || 0;
|
return total + slate.data?.objects?.length || 0;
|
||||||
@ -540,14 +486,8 @@ export default class Profile extends React.Component {
|
|||||||
onUpdateViewer={this.props.onUpdateViewer}
|
onUpdateViewer={this.props.onUpdateViewer}
|
||||||
resources={this.props.resources}
|
resources={this.props.resources}
|
||||||
viewer={this.props.viewer}
|
viewer={this.props.viewer}
|
||||||
objects={
|
objects={this.state.publicFiles}
|
||||||
this.state.fileTab === 0
|
isOwner={false}
|
||||||
? this.props.creator.library[0].children
|
|
||||||
: this.state.fileTab === 1
|
|
||||||
? this.state.publicFiles
|
|
||||||
: this.state.pseudoPrivateFiles
|
|
||||||
}
|
|
||||||
isOwner={isOwner}
|
|
||||||
onAction={this.props.onAction}
|
onAction={this.props.onAction}
|
||||||
mobile={this.props.mobile}
|
mobile={this.props.mobile}
|
||||||
external={this.props.external}
|
external={this.props.external}
|
||||||
@ -624,14 +564,6 @@ export default class Profile extends React.Component {
|
|||||||
{this.state.tab === 0 ? (
|
{this.state.tab === 0 ? (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ display: `flex` }}>
|
<div style={{ display: `flex` }}>
|
||||||
{isOwner && (
|
|
||||||
<SecondaryTabGroup
|
|
||||||
tabs={["All files", "Everyone can view", "Link access only"]}
|
|
||||||
value={this.state.fileTab}
|
|
||||||
onChange={(value) => this.setState({ fileTab: value })}
|
|
||||||
style={{ margin: "0 0 24px 0" }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<SecondaryTabGroup
|
<SecondaryTabGroup
|
||||||
tabs={[
|
tabs={[
|
||||||
<SVG.GridView height="24px" style={{ display: "block" }} />,
|
<SVG.GridView height="24px" style={{ display: "block" }} />,
|
||||||
@ -642,23 +574,19 @@ export default class Profile extends React.Component {
|
|||||||
style={{ margin: "0 0 24px 0", justifyContent: "flex-end" }}
|
style={{ margin: "0 0 24px 0", justifyContent: "flex-end" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!!dataItems.length ? (
|
{this.state.publicFiles.length ? (
|
||||||
<DataView
|
<DataView
|
||||||
onAction={this.props.onAction}
|
onAction={this.props.onAction}
|
||||||
viewer={this.props.viewer}
|
viewer={this.props.viewer}
|
||||||
isOwner={isOwner}
|
isOwner={isOwner}
|
||||||
items={dataItems}
|
items={this.state.publicFiles}
|
||||||
onUpdateViewer={this.props.onUpdateViewer}
|
onUpdateViewer={this.props.onUpdateViewer}
|
||||||
view={this.state.view}
|
view={this.state.view}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<EmptyState>
|
<EmptyState>
|
||||||
<FileTypeGroup />
|
<FileTypeGroup />
|
||||||
<div style={{ marginTop: 24 }}>
|
<div style={{ marginTop: 24 }}>This user does not have any public files yet</div>
|
||||||
{isOwner
|
|
||||||
? `Drag and drop files into Slate to upload`
|
|
||||||
: `This user does not have any public files yet`}
|
|
||||||
</div>
|
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -710,30 +638,18 @@ export default class Profile extends React.Component {
|
|||||||
onChange={(value) => this.setState({ peerTab: value })}
|
onChange={(value) => this.setState({ peerTab: value })}
|
||||||
style={{ margin: "0 0 24px 0" }}
|
style={{ margin: "0 0 24px 0" }}
|
||||||
/>
|
/>
|
||||||
{this.state.peerTab === 0 ? (
|
|
||||||
<div>
|
<div>
|
||||||
{following?.length ? (
|
{peers?.length ? (
|
||||||
following
|
peers
|
||||||
) : (
|
) : (
|
||||||
<EmptyState>
|
<EmptyState>
|
||||||
<SVG.Users height="24px" style={{ marginBottom: 24 }} />
|
<SVG.Users height="24px" style={{ marginBottom: 24 }} />
|
||||||
This user is not following anyone yet
|
{this.state.peerTab === 0
|
||||||
|
? "This user is not following anyone yet"
|
||||||
|
: "This user does not have any followers yet"}
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
|
||||||
{this.state.peerTab === 1 ? (
|
|
||||||
<div>
|
|
||||||
{followers?.length ? (
|
|
||||||
followers
|
|
||||||
) : (
|
|
||||||
<EmptyState>
|
|
||||||
<SVG.Users height="24px" style={{ marginBottom: 24 }} />
|
|
||||||
This user does not have any followers yet
|
|
||||||
</EmptyState>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<input
|
<input
|
||||||
readOnly
|
readOnly
|
||||||
ref={(c) => {
|
ref={(c) => {
|
||||||
|
@ -374,57 +374,58 @@ export class SlateLayout extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
componentDidUpdate = async (prevProps) => {
|
componentDidUpdate = async (prevProps) => {
|
||||||
if (prevProps.slateId !== this.props.slateId) {
|
// if (prevProps.slateId !== this.props.slateId) {
|
||||||
//NOTE(martina): to handle when you navigate between two slates, so it registers the change properly
|
// //NOTE(martina): to handle when you navigate between two slates, so it registers the change properly
|
||||||
await this.setState({ show: false });
|
// await this.setState({ show: false });
|
||||||
let defaultLayout = this.props.layout ? this.props.defaultLayout : true;
|
// let defaultLayout = this.props.layout ? this.props.defaultLayout : true;
|
||||||
let fileNames = this.props.fileNames;
|
// let fileNames = this.props.fileNames;
|
||||||
let layout;
|
// let layout;
|
||||||
if (this.props.layout) {
|
// if (this.props.layout) {
|
||||||
layout = await this.repairLayout(this.props.items, {
|
// layout = await this.repairLayout(this.props.items, {
|
||||||
defaultLayout,
|
// defaultLayout,
|
||||||
fileNames,
|
// fileNames,
|
||||||
layout: this.props.layout,
|
// layout: this.props.layout,
|
||||||
});
|
// });
|
||||||
if (layout) {
|
// if (layout) {
|
||||||
this.props.onSaveLayout(
|
// this.props.onSaveLayout(
|
||||||
{
|
// {
|
||||||
ver: "2.0",
|
// ver: "2.0",
|
||||||
fileNames,
|
// fileNames,
|
||||||
defaultLayout,
|
// defaultLayout,
|
||||||
layout,
|
// layout,
|
||||||
},
|
// },
|
||||||
true
|
// true
|
||||||
);
|
// );
|
||||||
} else {
|
// } else {
|
||||||
layout = this.props.layout;
|
// layout = this.props.layout;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
layout = generateLayout(this.props.items);
|
// layout = generateLayout(this.props.items);
|
||||||
await this.setState({ layout, items: this.props.items });
|
// await this.setState({ layout, items: this.props.items });
|
||||||
layout = await this.calculateLayout(layout);
|
// layout = await this.calculateLayout(layout);
|
||||||
this.props.onSaveLayout(
|
// this.props.onSaveLayout(
|
||||||
{
|
// {
|
||||||
ver: "2.0",
|
// ver: "2.0",
|
||||||
fileNames,
|
// fileNames,
|
||||||
defaultLayout,
|
// defaultLayout,
|
||||||
layout,
|
// layout,
|
||||||
},
|
// },
|
||||||
true
|
// true
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
await this.setState({
|
// await this.setState({
|
||||||
items: this.props.items,
|
// items: this.props.items,
|
||||||
layout,
|
// layout,
|
||||||
prevLayouts: [],
|
// prevLayouts: [],
|
||||||
zIndexMax: layout && layout.length ? Math.max(...layout.map((pos) => pos.z)) + 1 : 1,
|
// zIndexMax: layout && layout.length ? Math.max(...layout.map((pos) => pos.z)) + 1 : 1,
|
||||||
fileNames,
|
// fileNames,
|
||||||
defaultLayout,
|
// defaultLayout,
|
||||||
editing: false,
|
// editing: false,
|
||||||
show: true,
|
// show: true,
|
||||||
});
|
// });
|
||||||
this.calculateContainer();
|
// this.calculateContainer();
|
||||||
} else if (prevProps.items.length !== this.props.items.length) {
|
// }
|
||||||
|
if (prevProps.items.length !== this.props.items.length) {
|
||||||
//NOTE(martina): to handle when items are added / deleted from the slate, and recalculate the layout
|
//NOTE(martina): to handle when items are added / deleted from the slate, and recalculate the layout
|
||||||
//NOTE(martina): if there is a case that allows simultaneous add / delete (aka modify but same length), this will not work.
|
//NOTE(martina): if there is a case that allows simultaneous add / delete (aka modify but same length), this will not work.
|
||||||
//would need to replace it with event listener + custom events
|
//would need to replace it with event listener + custom events
|
||||||
|
@ -51,7 +51,7 @@ export default class ProfilePage extends React.Component {
|
|||||||
<WebsitePrototypeWrapper title={title} description={description} url={url} image={image}>
|
<WebsitePrototypeWrapper title={title} description={description} url={url} image={image}>
|
||||||
<WebsitePrototypeHeader />
|
<WebsitePrototypeHeader />
|
||||||
<div css={STYLES_ROOT}>
|
<div css={STYLES_ROOT}>
|
||||||
<Profile {...this.props} buttons={buttons} external />
|
<Profile {...this.props} buttons={buttons} isOwner={false} external />
|
||||||
</div>
|
</div>
|
||||||
{this.state.visible && (
|
{this.state.visible && (
|
||||||
<div>
|
<div>
|
||||||
|
@ -322,6 +322,7 @@ export default class SlatePage extends React.Component {
|
|||||||
<SlateLayout
|
<SlateLayout
|
||||||
external
|
external
|
||||||
slateId={this.props.slate.id}
|
slateId={this.props.slate.id}
|
||||||
|
key={this.props.slate.id}
|
||||||
layout={layouts && layouts.ver === "2.0" ? layouts.layout : null}
|
layout={layouts && layouts.ver === "2.0" ? layouts.layout : null}
|
||||||
onSaveLayout={this._handleSave}
|
onSaveLayout={this._handleSave}
|
||||||
isOwner={false}
|
isOwner={false}
|
||||||
|
@ -97,6 +97,8 @@ export default class SceneProfile extends React.Component {
|
|||||||
creator={
|
creator={
|
||||||
this.state.profile.id === this.props.viewer.id ? this.props.viewer : this.state.profile
|
this.state.profile.id === this.props.viewer.id ? this.props.viewer : this.state.profile
|
||||||
}
|
}
|
||||||
|
isOwner={this.state.profile.id === this.props.viewer.id}
|
||||||
|
key={this.state.profile.id}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -363,6 +363,7 @@ class SlatePage extends React.Component {
|
|||||||
) : (
|
) : (
|
||||||
<div style={{ marginTop: isOwner ? 24 : 48 }}>
|
<div style={{ marginTop: isOwner ? 24 : 48 }}>
|
||||||
<SlateLayout
|
<SlateLayout
|
||||||
|
key={this.props.current.id}
|
||||||
current={this.props.current}
|
current={this.props.current}
|
||||||
onUpdateViewer={this.props.onUpdateViewer}
|
onUpdateViewer={this.props.onUpdateViewer}
|
||||||
viewer={this.props.viewer}
|
viewer={this.props.viewer}
|
||||||
|
Loading…
Reference in New Issue
Block a user