mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-23 09:01:56 +03:00
optimistic updates
This commit is contained in:
parent
91c47f0776
commit
e849324486
@ -69,6 +69,7 @@ export const init = ({ resource = "", viewer, onUpdate }) => {
|
||||
}
|
||||
|
||||
if (type === "UPDATE" && onUpdate) {
|
||||
console.log("websocket on update");
|
||||
onUpdate(data);
|
||||
}
|
||||
});
|
||||
|
@ -183,7 +183,7 @@ export const deleteFiles = async (fileCids, fileIds = [], noAlert) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
Events.dispatchMessage({ message: "Files successfully deleted!", status: "INFO" });
|
||||
// Events.dispatchMessage({ message: "Files successfully deleted!", status: "INFO" });
|
||||
|
||||
return response;
|
||||
}
|
||||
|
@ -147,11 +147,24 @@ export default class ApplicationPage extends React.Component {
|
||||
}
|
||||
|
||||
_handleUpdateViewer = (newViewerState) => {
|
||||
if (this.state.viewer && newViewerState.id && newViewerState.id === this.state.viewer.id) {
|
||||
this.setState({
|
||||
viewer: { ...this.state.viewer, ...newViewerState, type: "VIEWER" },
|
||||
});
|
||||
}
|
||||
// let setAsyncState = (newState) =>
|
||||
// new Promise((resolve) =>
|
||||
// this.setState(
|
||||
// {
|
||||
// viewer: { ...this.state.viewer, ...newState, type: "VIEWER" },
|
||||
// },
|
||||
// resolve
|
||||
// )
|
||||
// );
|
||||
// await setAsyncState(newViewerState);
|
||||
|
||||
this.setState({
|
||||
viewer: { ...this.state.viewer, ...newViewerState, type: "VIEWER" },
|
||||
});
|
||||
};
|
||||
|
||||
_handleUpdateData = ({ data }) => {
|
||||
this.setState({ data });
|
||||
};
|
||||
|
||||
_handleSetupWebsocket = async () => {
|
||||
@ -424,12 +437,6 @@ export default class ApplicationPage extends React.Component {
|
||||
return false;
|
||||
};
|
||||
|
||||
_handleViewerChange = (e) => {
|
||||
this.setState({
|
||||
viewer: { ...this.state.viewer, [e.target.name]: e.target.value },
|
||||
});
|
||||
};
|
||||
|
||||
_handleSelectedChange = (e) => {
|
||||
this.setState({
|
||||
selected: { ...this.state.selected, [e.target.name]: e.target.value },
|
||||
@ -484,10 +491,6 @@ export default class ApplicationPage extends React.Component {
|
||||
return alert(JSON.stringify(options));
|
||||
};
|
||||
|
||||
_handleUpdateData = ({ data }) => {
|
||||
this.setState({ data });
|
||||
};
|
||||
|
||||
_handleNavigateTo = (next, data = null, redirect = false) => {
|
||||
if (next.id) {
|
||||
window.history.replaceState(
|
||||
@ -582,6 +585,7 @@ export default class ApplicationPage extends React.Component {
|
||||
|
||||
render() {
|
||||
// NOTE(jim): Not authenticated.
|
||||
console.log(this.state.viewer);
|
||||
if (!this.state.viewer) {
|
||||
return (
|
||||
<WebsitePrototypeWrapper
|
||||
@ -630,12 +634,12 @@ export default class ApplicationPage extends React.Component {
|
||||
viewer: this.state.viewer,
|
||||
selected: this.state.selected,
|
||||
onSelectedChange: this._handleSelectedChange,
|
||||
onViewerChange: this._handleViewerChange,
|
||||
onAction: this._handleAction,
|
||||
onUpload: this._handleUploadFiles,
|
||||
onBack: this._handleBack,
|
||||
onForward: this._handleForward,
|
||||
onUpdateData: this._handleUpdateData,
|
||||
onUpdateViewer: this._handleUpdateViewer,
|
||||
sceneId: current.target.id,
|
||||
mobile: this.state.mobile,
|
||||
resources: this.props.resources,
|
||||
@ -654,6 +658,7 @@ export default class ApplicationPage extends React.Component {
|
||||
onCancel: this._handleDismissSidebar,
|
||||
onUpload: this._handleUploadFiles,
|
||||
onAction: this._handleAction,
|
||||
onUpdateViewer: this._handleUpdateViewer,
|
||||
resources: this.props.resources,
|
||||
});
|
||||
}
|
||||
@ -682,6 +687,7 @@ export default class ApplicationPage extends React.Component {
|
||||
{scene}
|
||||
</ApplicationLayout>
|
||||
<GlobalCarousel
|
||||
onUpdateViewer={this._handleUpdateViewer}
|
||||
resources={this.props.resources}
|
||||
viewer={this.state.viewer}
|
||||
current={
|
||||
|
@ -289,22 +289,30 @@ export default class CarouselSidebarData extends React.Component {
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
_handleDelete = async (cid) => {
|
||||
_handleDelete = (cid) => {
|
||||
const message = `Are you sure you want to delete this? It will be deleted from your slates as well`;
|
||||
if (!window.confirm(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.setState({ loading: cid });
|
||||
let library = this.props.viewer.library;
|
||||
library[0].children = library[0].children.filter((obj) => obj.cid !== cid);
|
||||
this.props.onUpdateViewer({ library });
|
||||
|
||||
// await this.setState({ loading: cid });
|
||||
|
||||
// NOTE(jim): Accepts ID as well if CID can't be found.
|
||||
// Since our IDS are unique.
|
||||
await UserBehaviors.deleteFiles(cid, this.props.data.id);
|
||||
this.setState({ loading: false });
|
||||
UserBehaviors.deleteFiles(cid, this.props.data.id);
|
||||
// this.setState({ loading: false });
|
||||
};
|
||||
|
||||
_handleAdd = async (slate) => {
|
||||
await this.setState({ pickerLoading: slate.id });
|
||||
this.setState({
|
||||
selected: { ...this.state.selected, [slate.id]: !this.state.selected[slate.id] },
|
||||
// pickerLoading: null,
|
||||
});
|
||||
// await this.setState({ pickerLoading: slate.id });
|
||||
if (this.state.selected[slate.id]) {
|
||||
await UserBehaviors.removeFromSlate({ slate, ids: [this.props.data.id] });
|
||||
} else {
|
||||
@ -314,10 +322,6 @@ export default class CarouselSidebarData extends React.Component {
|
||||
fromSlate: this.props.fromSlate,
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
selected: { ...this.state.selected, [slate.id]: !this.state.selected[slate.id] },
|
||||
pickerLoading: null,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -286,8 +286,9 @@ export default class CarouselSidebarSlate extends React.Component {
|
||||
this.setState({ loading: false });
|
||||
};
|
||||
|
||||
_handleDelete = async (cid) => {
|
||||
_handleDelete = (cid) => {
|
||||
if (this.props.external || !this.props.isOwner) return;
|
||||
|
||||
if (
|
||||
!window.confirm(
|
||||
"Are you sure you want to delete this? It will be removed from all your slates too."
|
||||
@ -295,13 +296,22 @@ export default class CarouselSidebarSlate extends React.Component {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
console.log(this.props.data);
|
||||
|
||||
await this.setState({ loading: "deleting" });
|
||||
let slates = this.props.viewer.slates;
|
||||
let slateId = this.props.current.id;
|
||||
for (let slate of slates) {
|
||||
if (slate.id === slateId) {
|
||||
slate.data.objects = slate.data.objects.filter((obj) => obj.cid !== cid);
|
||||
this.props.onUpdateViewer({ slates });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// await this.setState({ loading: "deleting" });
|
||||
// NOTE(jim): Accepts ID as well if CID can't be found.
|
||||
// Since our IDS are unique.
|
||||
await UserBehaviors.deleteFiles(cid, this.props.data.id);
|
||||
this.setState({ loading: false });
|
||||
UserBehaviors.deleteFiles(cid, this.props.data.id);
|
||||
// this.setState({ loading: false });
|
||||
};
|
||||
|
||||
_toggleAccordion = (tab) => {
|
||||
@ -309,7 +319,11 @@ export default class CarouselSidebarSlate extends React.Component {
|
||||
};
|
||||
|
||||
_handleAdd = async (slate) => {
|
||||
await this.setState({ pickerLoading: slate.id });
|
||||
this.setState({
|
||||
selected: { ...this.state.selected, [slate.id]: !this.state.selected[slate.id] },
|
||||
// pickerLoading: null,
|
||||
});
|
||||
// await this.setState({ pickerLoading: slate.id });
|
||||
if (this.state.selected[slate.id]) {
|
||||
await UserBehaviors.removeFromSlate({ slate, ids: [this.props.data.id] });
|
||||
} else {
|
||||
@ -319,10 +333,6 @@ export default class CarouselSidebarSlate extends React.Component {
|
||||
fromSlate: this.props.fromSlate,
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
selected: { ...this.state.selected, [slate.id]: !this.state.selected[slate.id] },
|
||||
pickerLoading: null,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -341,7 +341,7 @@ export default class DataView extends React.Component {
|
||||
return;
|
||||
};
|
||||
|
||||
_handleDelete = async (cid, id) => {
|
||||
_handleDelete = (cid, id) => {
|
||||
const message = `Are you sure you want to delete these files? They will be deleted from your slates as well`;
|
||||
if (!window.confirm(message)) {
|
||||
return;
|
||||
@ -365,10 +365,16 @@ export default class DataView extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
await this._handleLoading({ cids });
|
||||
await UserBehaviors.deleteFiles(cids, ids);
|
||||
this._handleLoading({ cids });
|
||||
await this.setState({ checked: {} });
|
||||
let library = this.props.viewer.library;
|
||||
library[0].children = library[0].children.filter(
|
||||
(obj) => !ids.includes(obj.id) && !cids.includes(obj.cid)
|
||||
);
|
||||
this.props.onUpdateViewer({ library });
|
||||
|
||||
// await this._handleLoading({ cids });
|
||||
UserBehaviors.deleteFiles(cids, ids);
|
||||
// this._handleLoading({ cids });
|
||||
this.setState({ checked: {} });
|
||||
};
|
||||
|
||||
_handleSelect = (index) => {
|
||||
|
@ -1037,6 +1037,17 @@ export class SlateLayout extends React.Component {
|
||||
}
|
||||
this.setState({ checked: {} });
|
||||
}
|
||||
|
||||
let slates = this.props.viewer.slates;
|
||||
let slateId = this.props.current.id;
|
||||
for (let slate of slates) {
|
||||
if (slate.id === slateId) {
|
||||
slate.data.objects = slate.data.objects.filter((obj) => !ids.includes(obj.id));
|
||||
this.props.onUpdateViewer({ slates });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UserBehaviors.removeFromSlate({ slate: this.props.current, ids });
|
||||
};
|
||||
|
||||
@ -1063,10 +1074,22 @@ export class SlateLayout extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
await this._handleLoading({ cids });
|
||||
let slates = this.props.viewer.slates;
|
||||
let slateId = this.props.current.id;
|
||||
for (let slate of slates) {
|
||||
if (slate.id === slateId) {
|
||||
slate.data.objects = slate.data.objects.filter(
|
||||
(obj) => !ids.includes(obj.id) && !cids.includes(obj.cid)
|
||||
);
|
||||
this.props.onUpdateViewer({ slates });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// await this._handleLoading({ cids });
|
||||
await UserBehaviors.deleteFiles(cids, ids);
|
||||
this._handleLoading({ cids });
|
||||
await this.setState({ checked: {} });
|
||||
this.setState({ checked: {} });
|
||||
};
|
||||
|
||||
_handleLoading = ({ cids }) => {
|
||||
|
@ -140,9 +140,7 @@ export class SlatePicker extends React.Component {
|
||||
onClick={() => this.props.onAdd(slate)}
|
||||
>
|
||||
<div css={STYLES_ICON_BOX}>
|
||||
{this.props.loading && this.props.loading === slate.id ? (
|
||||
<LoaderSpinner style={{ height: 20, width: 20, margin: "2px 8px 2px 2px" }} />
|
||||
) : selected[slate.id] ? (
|
||||
{selected[slate.id] ? (
|
||||
<SVG.Slate
|
||||
height="24px"
|
||||
style={{
|
||||
|
@ -57,7 +57,8 @@ export default class SidebarAddFileToSlate extends React.Component {
|
||||
};
|
||||
|
||||
_handleSubmit = async () => {
|
||||
await this.setState({ loading: true });
|
||||
this.props.onCancel();
|
||||
// await this.setState({ loading: true });
|
||||
for (let slate of Object.values(this.state.selected)) {
|
||||
if (!slate) continue;
|
||||
await UserBehaviors.addToSlate({
|
||||
@ -66,8 +67,7 @@ export default class SidebarAddFileToSlate extends React.Component {
|
||||
fromSlate: this.props.sidebarData.fromSlate,
|
||||
});
|
||||
}
|
||||
this.setState({ loading: false });
|
||||
this.props.onCancel();
|
||||
// this.setState({ loading: false });
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -53,8 +53,20 @@ export default class SidebarSingleSlateSettings extends React.Component {
|
||||
};
|
||||
|
||||
_handleSubmit = async () => {
|
||||
this.setState({ loading: true });
|
||||
// this.setState({ loading: true });
|
||||
|
||||
let slates = this.props.viewer.slates;
|
||||
for (let slate of slates) {
|
||||
if (slate.id === this.props.current.id) {
|
||||
slate.data.name = this.state.name;
|
||||
slate.data.public = this.state.public;
|
||||
slate.data.body = this.state.body;
|
||||
this.props.onUpdateViewer({ slates });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.props.onCancel();
|
||||
const response = await Actions.updateSlate({
|
||||
id: this.props.current.id,
|
||||
data: {
|
||||
@ -65,10 +77,9 @@ export default class SidebarSingleSlateSettings extends React.Component {
|
||||
});
|
||||
|
||||
if (Events.hasError(response)) {
|
||||
this.setState({ loading: false });
|
||||
// this.setState({ loading: false });
|
||||
return;
|
||||
}
|
||||
this.props.onCancel();
|
||||
};
|
||||
|
||||
_handleCancel = () => {
|
||||
|
@ -392,6 +392,7 @@ export class GlobalCarousel extends React.Component {
|
||||
<CarouselSidebarData
|
||||
viewer={this.props.viewer}
|
||||
display={this.state.showSidebar && !isUnityGame ? "block" : "none"}
|
||||
onUpdateViewer={this.props.onUpdateViewer}
|
||||
onClose={this._handleClose}
|
||||
key={data.id}
|
||||
saving={this.state.saving}
|
||||
@ -405,6 +406,9 @@ export class GlobalCarousel extends React.Component {
|
||||
) : (
|
||||
<CarouselSidebarSlate
|
||||
display={this.state.showSidebar && !isUnityGame ? "block" : "none"}
|
||||
viewer={this.props.viewer}
|
||||
onUpdateViewer={this.props.onUpdateViewer}
|
||||
current={this.props.current}
|
||||
key={data.id}
|
||||
saving={this.state.saving}
|
||||
loading={this.state.loading}
|
||||
|
@ -99,9 +99,11 @@ export default async (req, res) => {
|
||||
return res.status(500).send({ decorator: "SERVER_UPDATE_SLATE", error: true });
|
||||
}
|
||||
|
||||
let slates = await Data.getSlatesByUserId({ userId: id });
|
||||
if (slates) {
|
||||
ViewerManager.hydratePartialSlates(slates, id);
|
||||
if (!layoutOnly && isOwner) {
|
||||
let slates = await Data.getSlatesByUserId({ userId: id });
|
||||
if (slates) {
|
||||
ViewerManager.hydratePartialSlates(slates, id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!layoutOnly && !req.body.data.autoSave) {
|
||||
|
@ -39,6 +39,7 @@ export default class SceneFilesFolder extends React.Component {
|
||||
onAction={this.props.onAction}
|
||||
viewer={this.props.viewer}
|
||||
items={this.props.viewer.library[0].children}
|
||||
onUpdateViewer={this.props.onUpdateViewer}
|
||||
/>
|
||||
) : (
|
||||
<EmptyState>
|
||||
|
@ -11,7 +11,6 @@ import { css } from "@emotion/react";
|
||||
|
||||
import ScenePage from "~/components/core/ScenePage";
|
||||
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
|
||||
import DataView from "~/components/core/DataView";
|
||||
import ScenePageHeader from "~/components/core/ScenePageHeader";
|
||||
|
||||
const STYLES_VIDEO_BIG = css`
|
||||
|
@ -13,14 +13,26 @@ const STYLES_BUTTONS = css`
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const STATUS_BUTTON_MAP = {
|
||||
trusted: "Remove peer",
|
||||
untrusted: "Add peer",
|
||||
sent: "Cancel request",
|
||||
received: "Accept request",
|
||||
};
|
||||
|
||||
export default class SceneProfile extends React.Component {
|
||||
state = {
|
||||
isFollowing: !!this.props.viewer.subscriptions.filter((entry) => {
|
||||
return entry.target_user_id === this.props.data.id;
|
||||
}).length,
|
||||
};
|
||||
|
||||
componentDidUpdate = (prevProps) => {
|
||||
if (
|
||||
this.props.data.id !== prevProps.data.id ||
|
||||
this.props.viewer.subscriptions !== prevProps.viewer.subscriptions
|
||||
) {
|
||||
this.setState({
|
||||
isFollowing: !!this.props.viewer.subscriptions.filter((entry) => {
|
||||
return entry.target_user_id === this.props.data.id;
|
||||
}).length,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// _handleTrust = async (trustStatus, trustId) => {
|
||||
// if (trustStatus === "untrusted" || trustStatus === "sent") {
|
||||
// await Actions.createTrustRelationship({
|
||||
@ -38,46 +50,16 @@ export default class SceneProfile extends React.Component {
|
||||
// };
|
||||
|
||||
_handleFollow = async () => {
|
||||
this.setState({ isFollowing: !this.state.isFollowing });
|
||||
await Actions.createSubscription({
|
||||
userId: this.props.data.id,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let trustId, followStatus, relation;
|
||||
// let trustStatus = "untrusted";
|
||||
let viewer = this.props.viewer;
|
||||
// let trust = viewer.trusted.filter((entry) => {
|
||||
// return entry.target_user_id === this.props.data.id;
|
||||
// });
|
||||
// if (trust.length) {
|
||||
// relation = trust[0];
|
||||
// trustId = relation.id;
|
||||
// if (relation.data.verified) {
|
||||
// trustStatus = "trusted";
|
||||
// } else {
|
||||
// trustStatus = "sent";
|
||||
// }
|
||||
// }
|
||||
// let pendingTrust = viewer.pendingTrusted.filter((entry) => {
|
||||
// return entry.owner_user_id === this.props.data.id;
|
||||
// });
|
||||
// if (pendingTrust.length) {
|
||||
// relation = pendingTrust[0];
|
||||
// trustId = relation.id;
|
||||
// if (pendingTrust[0].data.verified) {
|
||||
// trustStatus = "trusted";
|
||||
// } else {
|
||||
// trustStatus = "received";
|
||||
// }
|
||||
// }
|
||||
followStatus = !!viewer.subscriptions.filter((entry) => {
|
||||
return entry.target_user_id === this.props.data.id;
|
||||
}).length;
|
||||
|
||||
let buttons = (
|
||||
<div css={STYLES_BUTTONS}>
|
||||
{followStatus ? (
|
||||
{this.state.isFollowing ? (
|
||||
<ButtonSecondary style={{ marginRight: 8 }} onClick={this._handleFollow}>
|
||||
Unfollow
|
||||
</ButtonSecondary>
|
||||
|
@ -141,6 +141,15 @@ export default class SceneSlate extends React.Component {
|
||||
data.layouts = layouts;
|
||||
}
|
||||
if (preview) {
|
||||
let slates = this.props.viewer.slates;
|
||||
let slateId = this.props.current.id;
|
||||
for (let slate of slates) {
|
||||
if (slate.id === slateId) {
|
||||
slate.data.preview = preview;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.props.onUpdateViewer({ slates });
|
||||
data.preview = preview;
|
||||
}
|
||||
const response = await Actions.updateSlate({
|
||||
@ -196,7 +205,6 @@ export default class SceneSlate extends React.Component {
|
||||
render() {
|
||||
const { user, data } = this.props.current;
|
||||
const { body = "", preview } = data;
|
||||
console.log(body);
|
||||
let objects = this.props.current.data.objects;
|
||||
let layouts = this.props.current.data.layouts;
|
||||
const isPublic = data.public;
|
||||
@ -313,10 +321,12 @@ export default class SceneSlate extends React.Component {
|
||||
: ""
|
||||
}
|
||||
current={this.props.current}
|
||||
onUpdateViewer={this.props.onUpdateViewer}
|
||||
viewer={this.props.viewer}
|
||||
slateId={this.props.current.id}
|
||||
layout={layouts && layouts.ver === "2.0" ? layouts.layout || [] : null}
|
||||
onSaveLayout={this._handleSaveLayout}
|
||||
onSave={this._handleSave}
|
||||
isOwner={this.state.isOwner}
|
||||
fileNames={layouts && layouts.ver === "2.0" ? layouts.fileNames : false}
|
||||
preview={preview}
|
||||
|
Loading…
Reference in New Issue
Block a user