mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-26 02:24:44 +03:00
added carousel to profiles and fixed not updating bug
This commit is contained in:
parent
7f4f6a4b04
commit
c4301e74b8
@ -52,7 +52,6 @@ import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper";
|
|||||||
|
|
||||||
import { GlobalModal } from "~/components/system/components/GlobalModal";
|
import { GlobalModal } from "~/components/system/components/GlobalModal";
|
||||||
import { OnboardingModal } from "~/components/core/OnboardingModal";
|
import { OnboardingModal } from "~/components/core/OnboardingModal";
|
||||||
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
|
|
||||||
import { SearchModal } from "~/components/core/SearchModal";
|
import { SearchModal } from "~/components/core/SearchModal";
|
||||||
import { Alert } from "~/components/core/Alert";
|
import { Alert } from "~/components/core/Alert";
|
||||||
import { announcements } from "~/components/core/OnboardingModal";
|
import { announcements } from "~/components/core/OnboardingModal";
|
||||||
@ -690,15 +689,6 @@ export default class ApplicationPage extends React.Component {
|
|||||||
>
|
>
|
||||||
{scene}
|
{scene}
|
||||||
</ApplicationLayout>
|
</ApplicationLayout>
|
||||||
<GlobalCarousel
|
|
||||||
onUpdateViewer={this._handleUpdateViewer}
|
|
||||||
resources={this.props.resources}
|
|
||||||
viewer={this.state.viewer}
|
|
||||||
current={this.state.data}
|
|
||||||
slates={this.state.viewer.slates}
|
|
||||||
onAction={this._handleAction}
|
|
||||||
mobile={this.props.mobile}
|
|
||||||
/>
|
|
||||||
<GlobalModal />
|
<GlobalModal />
|
||||||
<SearchModal
|
<SearchModal
|
||||||
viewer={this.state.viewer}
|
viewer={this.state.viewer}
|
||||||
|
@ -82,6 +82,7 @@ const STYLES_DISMISS_BOX = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_META = css`
|
const STYLES_META = css`
|
||||||
|
text-align: start;
|
||||||
padding: 14px 0px 8px 0px;
|
padding: 14px 0px 8px 0px;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
`;
|
`;
|
||||||
@ -343,6 +344,7 @@ export default class CarouselSidebarData extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handleDelete = (cid) => {
|
_handleDelete = (cid) => {
|
||||||
|
if (!this.props.isOwner) return;
|
||||||
const message = `Are you sure you want to delete this? It will be deleted from your slates as well`;
|
const message = `Are you sure you want to delete this? It will be deleted from your slates as well`;
|
||||||
if (!window.confirm(message)) {
|
if (!window.confirm(message)) {
|
||||||
return;
|
return;
|
||||||
@ -384,7 +386,6 @@ export default class CarouselSidebarData extends React.Component {
|
|||||||
const isVisible = this.state.inPublicSlates || this.state.isPublic;
|
const isVisible = this.state.inPublicSlates || this.state.isPublic;
|
||||||
let selected = this.state.selected;
|
let selected = this.state.selected;
|
||||||
if (this.state.inPublicSlates) {
|
if (this.state.inPublicSlates) {
|
||||||
console.log("in public slates");
|
|
||||||
const slateIds = Object.entries(this.state.selected)
|
const slateIds = Object.entries(this.state.selected)
|
||||||
.filter((entry) => entry[1])
|
.filter((entry) => entry[1])
|
||||||
.map((entry) => entry[0]);
|
.map((entry) => entry[0]);
|
||||||
@ -410,7 +411,6 @@ export default class CarouselSidebarData extends React.Component {
|
|||||||
public: !isVisible,
|
public: !isVisible,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log(response);
|
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
this.setState({ inPublicSlates: false, isPublic: false, selected });
|
this.setState({ inPublicSlates: false, isPublic: false, selected });
|
||||||
} else {
|
} else {
|
||||||
@ -445,7 +445,10 @@ export default class CarouselSidebarData extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</Boundary>
|
</Boundary>
|
||||||
) : (
|
) : (
|
||||||
<span css={STYLES_META_TITLE} target="_blank" onClick={this._handleEditFilename}>
|
<span
|
||||||
|
css={STYLES_META_TITLE}
|
||||||
|
onClick={this.props.external ? () => {} : this._handleEditFilename}
|
||||||
|
>
|
||||||
{this.state.name}
|
{this.state.name}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@ -462,37 +465,45 @@ export default class CarouselSidebarData extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div css={STYLES_ACTIONS}>
|
<div css={STYLES_ACTIONS}>
|
||||||
<div css={STYLES_ACTION} onClick={() => this._handleCopy(cid, "cidCopying")}>
|
{this.props.isOwner ? (
|
||||||
<SVG.CopyAndPaste height="24px" />
|
<div css={STYLES_ACTION} onClick={() => this._handleCopy(cid, "cidCopying")}>
|
||||||
<span style={{ marginLeft: 16 }}>
|
<SVG.CopyAndPaste height="24px" />
|
||||||
{this.state.loading === "cidCopying" ? "Copied!" : "Copy file CID"}
|
<span style={{ marginLeft: 16 }}>
|
||||||
</span>
|
{this.state.loading === "cidCopying" ? "Copied!" : "Copy file CID"}
|
||||||
</div>
|
</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
<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 gateway URL"}
|
{this.state.loading === "gatewayUrlCopying" ? "Copied!" : "Copy external URL"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div css={STYLES_ACTION} onClick={this._handleDownload}>
|
<div css={STYLES_ACTION} onClick={this._handleDownload}>
|
||||||
<SVG.Download height="24px" />
|
<SVG.Download height="24px" />
|
||||||
<span style={{ marginLeft: 16 }}>Download</span>
|
<span style={{ marginLeft: 16 }}>Download</span>
|
||||||
</div>
|
</div>
|
||||||
<div css={STYLES_ACTION} onClick={() => this._handleDelete(cid)}>
|
{this.props.isOwner ? (
|
||||||
<SVG.Trash height="24px" />
|
<div css={STYLES_ACTION} onClick={() => this._handleDelete(cid)}>
|
||||||
<span style={{ marginLeft: 16 }}>Delete</span>
|
<SVG.Trash height="24px" />
|
||||||
</div>
|
<span style={{ marginLeft: 16 }}>Delete</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div css={STYLES_SECTION_HEADER}>Connected Slates</div>
|
{this.props.external ? null : (
|
||||||
<SlatePicker
|
<React.Fragment>
|
||||||
dark
|
<div css={STYLES_SECTION_HEADER}>Connected Slates</div>
|
||||||
slates={this.props.slates}
|
<SlatePicker
|
||||||
onCreateSlate={this._handleCreateSlate}
|
dark
|
||||||
selectedColor={Constants.system.white}
|
slates={this.props.slates}
|
||||||
files={[this.props.data]}
|
onCreateSlate={this._handleCreateSlate}
|
||||||
selected={this.state.selected}
|
selectedColor={Constants.system.white}
|
||||||
onAdd={this._handleAdd}
|
files={[this.props.data]}
|
||||||
/>
|
selected={this.state.selected}
|
||||||
|
onAdd={this._handleAdd}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
{type && Validations.isPreviewableImage(type) ? null : (
|
{type && Validations.isPreviewableImage(type) ? null : (
|
||||||
<div>
|
<div>
|
||||||
<System.P css={STYLES_SECTION_HEADER} style={{ margin: "48px 0px 8px 0px" }}>
|
<System.P css={STYLES_SECTION_HEADER} style={{ margin: "48px 0px 8px 0px" }}>
|
||||||
@ -534,28 +545,32 @@ export default class CarouselSidebarData extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div css={STYLES_SECTION_HEADER} style={{ margin: "48px 0px 8px 0px" }}>
|
{this.props.isOwner ? (
|
||||||
Visibility
|
<React.Fragment>
|
||||||
</div>
|
<div css={STYLES_SECTION_HEADER} style={{ margin: "48px 0px 8px 0px" }}>
|
||||||
<div
|
Visibility
|
||||||
style={{
|
</div>
|
||||||
display: "flex",
|
<div
|
||||||
flexDirection: "row",
|
style={{
|
||||||
alignItems: "center",
|
display: "flex",
|
||||||
justifyContent: "space-between",
|
flexDirection: "row",
|
||||||
margin: "16px 0 16px 0",
|
alignItems: "center",
|
||||||
}}
|
justifyContent: "space-between",
|
||||||
>
|
margin: "16px 0 16px 0",
|
||||||
<div style={{ color: Constants.system.darkGray, lineHeight: "1.5" }}>
|
}}
|
||||||
{isVisible ? "Everyone" : "Link only"}
|
>
|
||||||
</div>
|
<div style={{ color: Constants.system.darkGray, lineHeight: "1.5" }}>
|
||||||
<Toggle dark active={isVisible} onChange={this._handleToggleVisibility} />
|
{isVisible ? "Everyone" : "Link only"}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ color: Constants.system.darkGray, marginTop: 8 }}>
|
<Toggle dark active={isVisible} onChange={this._handleToggleVisibility} />
|
||||||
{isVisible
|
</div>
|
||||||
? "This file is currently visible to everyone and searchable within Slate through public slates."
|
<div style={{ color: Constants.system.darkGray, marginTop: 8 }}>
|
||||||
: "This file is currently not visible to others unless they have the link."}
|
{isVisible
|
||||||
</div>
|
? "This file is currently visible to everyone and searchable within Slate through public slates."
|
||||||
|
: "This file is currently not visible to others unless they have the link."}
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
) : null}
|
||||||
<input
|
<input
|
||||||
css={STYLES_HIDDEN}
|
css={STYLES_HIDDEN}
|
||||||
ref={(c) => {
|
ref={(c) => {
|
||||||
|
@ -4,7 +4,14 @@ 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 { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
|
||||||
import { css } from "@emotion/react";
|
import { css } from "@emotion/react";
|
||||||
|
import { ButtonPrimary, ButtonSecondary } from "~/components/system/components/Buttons";
|
||||||
|
import { TabGroup, SecondaryTabGroup } from "~/components/core/TabGroup";
|
||||||
|
import { Boundary } from "~/components/system/components/fragments/Boundary";
|
||||||
|
import { PopoverNavigation } from "~/components/system/components/PopoverNavigation";
|
||||||
|
import { FileTypeGroup } from "~/components/core/FileTypeIcon";
|
||||||
|
//FOR TARA: try and group imports by style (import *, import { Whatever }, import Whatever). Just a neatness preference
|
||||||
|
|
||||||
import ProcessedText from "~/components/core/ProcessedText";
|
import ProcessedText from "~/components/core/ProcessedText";
|
||||||
import SlatePreviewBlocks from "~/components/core/SlatePreviewBlock";
|
import SlatePreviewBlocks from "~/components/core/SlatePreviewBlock";
|
||||||
@ -12,12 +19,6 @@ import CTATransition from "~/components/core/CTATransition";
|
|||||||
import DataView from "~/components/core/DataView";
|
import DataView from "~/components/core/DataView";
|
||||||
import EmptyState from "~/components/core/EmptyState";
|
import EmptyState from "~/components/core/EmptyState";
|
||||||
|
|
||||||
import { SceneUtils } from "three";
|
|
||||||
import { TabGroup, SecondaryTabGroup } from "~/components/core/TabGroup";
|
|
||||||
import { Boundary } from "~/components/system/components/fragments/Boundary";
|
|
||||||
import { PopoverNavigation } from "~/components/system/components/PopoverNavigation";
|
|
||||||
import { FileTypeGroup } from "~/components/core/FileTypeIcon";
|
|
||||||
|
|
||||||
const STYLES_PROFILE_BACKGROUND = css`
|
const STYLES_PROFILE_BACKGROUND = css`
|
||||||
background-color: ${Constants.system.white};
|
background-color: ${Constants.system.white};
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -60,7 +61,8 @@ const STYLES_INFO = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_PROFILE_IMAGE = css`
|
const STYLES_PROFILE_IMAGE = css`
|
||||||
background-color: ${Constants.system.white};
|
background-color: ${Constants.system.foreground};
|
||||||
|
${"" /* FOR TARA: I like to put a background color that stands out from the background so that in the case that the background image isn't found, it doesn't just show blank. It at least shows a square there */}
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: 50% 50%;
|
background-position: 50% 50%;
|
||||||
width: 120px;
|
width: 120px;
|
||||||
@ -108,8 +110,8 @@ const STYLES_STATS = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_STAT = css`
|
const STYLES_STAT = css`
|
||||||
margin-right: 8px;
|
margin: 0px 12px;
|
||||||
width: 112px;
|
${"" /* width: 112px; */}
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -233,70 +235,53 @@ export default class Profile extends React.Component {
|
|||||||
peerTab: 0,
|
peerTab: 0,
|
||||||
copyValue: "",
|
copyValue: "",
|
||||||
contextMenu: null,
|
contextMenu: null,
|
||||||
followingSlates: [],
|
|
||||||
publicSlates: [],
|
publicSlates: [],
|
||||||
publicFiles: [],
|
publicFiles: [],
|
||||||
pseudoPrivateFiles: [],
|
pseudoPrivateFiles: [],
|
||||||
};
|
isFollowing: this.props.external
|
||||||
|
? false
|
||||||
_handleCopy = (e, value) => {
|
: !!this.props.viewer.subscriptions.filter((entry) => {
|
||||||
e.stopPropagation();
|
return entry.target_user_id === this.props.data.id;
|
||||||
this.setState({ copyValue: value }, () => {
|
}).length,
|
||||||
this._ref.select();
|
//FOR TARA: here's an example of using the !! where it's needed. I want isFollowing to be true (if a subscription to this user was found) or false, not 0 or 1, so I use a !! to convert the number to a boolean
|
||||||
document.execCommand("copy");
|
|
||||||
this._handleHide();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
_handleHide = (e) => {
|
|
||||||
this.setState({ contextMenu: null });
|
|
||||||
};
|
|
||||||
|
|
||||||
_handleClick = (e, value) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (this.state.contextMenu === value) {
|
|
||||||
this._handleHide();
|
|
||||||
} else {
|
|
||||||
this.setState({ contextMenu: value });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_handleFollow = async (e, id) => {
|
|
||||||
this._handleHide();
|
|
||||||
e.stopPropagation();
|
|
||||||
await Actions.createSubscription({
|
|
||||||
userId: id,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount = async () => {
|
componentDidMount = async () => {
|
||||||
await this.filterByVisibility();
|
await this.filterByVisibility();
|
||||||
await this.fetchUsername();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidUpdate = async () => {
|
componentDidUpdate = async () => {
|
||||||
if (this.props.viewer?.library[0].children.length !== this.lastLength) {
|
if (
|
||||||
|
this.lastLength != null &&
|
||||||
|
this.props.creator?.library[0].children.length !== this.lastLength
|
||||||
|
) {
|
||||||
|
//FOR TARA: I just added the "this.lastLength != null" so that we don't get the double-call here where component did mount calls filterbyvisiblity,
|
||||||
|
//then filterbyvisibility changes the library length to not null,
|
||||||
|
//then componentdidupdate sees that the length has changed from null to some number, then calls filterbyvisibility again
|
||||||
|
//FOR TARA: I also made it this.props.creator rather than this.props.viewer. Not a big deal, but this is b/c if you are viewing someone else's profile and your OWN library changes, you shouldn't have to do filterbyvisibility again b/c it won't affect anything
|
||||||
this.filterByVisibility();
|
this.filterByVisibility();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchUsername = async () => {
|
//FOR TARA: you don't need to do actions.getserialized profile to get the username of the slate owner here. it was already accessible through subscription.slate.username, and you don't need to pass it in
|
||||||
let followingSlates = [];
|
//Without that call, it makes more sense to put this inside the render method so I moved this there now. You can delete this function
|
||||||
let subscriptions = this.props.creator.subscriptions ? this.props.creator.subscriptions : null;
|
// fetchUsername = async () => {
|
||||||
for (let subscription of subscriptions) {
|
// let followingSlates = [];
|
||||||
if (subscription.slate != null) {
|
// let subscriptions = this.props.creator.subscriptions ? this.props.creator.subscriptions : [];
|
||||||
followingSlates.push(subscription.slate);
|
// for (let subscription of subscriptions) {
|
||||||
}
|
// if (subscription.slate != null) {
|
||||||
}
|
// followingSlates.push(subscription.slate);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
for (let followingSlate of followingSlates) {
|
// for (let followingSlate of followingSlates) {
|
||||||
let id = { id: followingSlate.data.ownerId };
|
// let id = { id: followingSlate.data.ownerId };
|
||||||
let slateOwner = await Actions.getSerializedProfile(id);
|
// let slateOwner = await Actions.getSerializedProfile(id); //martina: do we need to do serialized? or just normal? Or some other way of getting teh username that's more efficient?
|
||||||
followingSlate.username = slateOwner.data?.username;
|
// followingSlate.username = slateOwner.data?.username;
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.setState({ followingSlates: followingSlates });
|
// this.setState({ followingSlates: followingSlates });
|
||||||
};
|
// };
|
||||||
|
|
||||||
filterByVisibility = async () => {
|
filterByVisibility = async () => {
|
||||||
let publicFiles = [];
|
let publicFiles = [];
|
||||||
@ -334,24 +319,53 @@ export default class Profile extends React.Component {
|
|||||||
publicFiles: publicFiles,
|
publicFiles: publicFiles,
|
||||||
pseudoPrivateFiles: pseudoPrivateFiles,
|
pseudoPrivateFiles: pseudoPrivateFiles,
|
||||||
});
|
});
|
||||||
this.lastLength = this.props.viewer?.library[0].children.length;
|
this.lastLength = this.props.creator?.library[0].children.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleCopy = (e, value) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
this.setState({ copyValue: value }, () => {
|
||||||
|
this._ref.select();
|
||||||
|
document.execCommand("copy");
|
||||||
|
this._handleHide();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleHide = (e) => {
|
||||||
|
this.setState({ contextMenu: null });
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleClick = (e, value) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (this.state.contextMenu === value) {
|
||||||
|
this._handleHide();
|
||||||
|
} else {
|
||||||
|
this.setState({ contextMenu: value });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleFollow = async (e, id) => {
|
||||||
|
this._handleHide();
|
||||||
|
e.stopPropagation();
|
||||||
|
await Actions.createSubscription({
|
||||||
|
userId: id,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const external = !this.props.onAction;
|
|
||||||
let data = this.props.creator ? this.props.creator : this.props.data;
|
|
||||||
let exploreSlates = this.props.exploreSlates;
|
|
||||||
let subscriptions = this.props.isOwner
|
|
||||||
? this.props.viewer.subscriptions
|
|
||||||
: this.props.creator.subscriptions
|
|
||||||
? this.props.creator.subscriptions
|
|
||||||
: null;
|
|
||||||
let subscribers = this.props.isOwner
|
|
||||||
? this.props.viewer.subscribers
|
|
||||||
: this.props.creator.subscribers
|
|
||||||
? this.props.creator.subscribers
|
|
||||||
: null;
|
|
||||||
let isOwner = this.props.creator.username === this.props.viewer?.username;
|
let isOwner = this.props.creator.username === this.props.viewer?.username;
|
||||||
|
let data = this.props.creator ? this.props.creator : this.props.data;
|
||||||
|
//FOR TARA: i made a chnage in scene profile so that if it is your own profile, creator is equivalent to viewer, so there is no longer a need to check for that here
|
||||||
|
//FOR TARA: also, it's always safer to make the "default" for an array an empty array, not null. Because if you try iterate over null, it will error.
|
||||||
|
let subscriptions = this.props.creator.subscriptions || [];
|
||||||
|
let subscribers = this.props.creator.subscribers || [];
|
||||||
|
|
||||||
|
//FOR TARA: this is where I moved the "fetchUsernames" function to
|
||||||
|
let followingSlates = subscriptions
|
||||||
|
.filter((relation) => {
|
||||||
|
return !!relation.target_slate_id;
|
||||||
|
})
|
||||||
|
.map((relation) => relation.slate);
|
||||||
|
|
||||||
let following = subscriptions
|
let following = subscriptions
|
||||||
.filter((relation) => {
|
.filter((relation) => {
|
||||||
@ -415,7 +429,7 @@ export default class Profile extends React.Component {
|
|||||||
<UserEntry
|
<UserEntry
|
||||||
key={relation.id}
|
key={relation.id}
|
||||||
user={relation.user}
|
user={relation.user}
|
||||||
button={button}
|
button={this.props.external ? null : button}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.props.onAction({
|
this.props.onAction({
|
||||||
type: "NAVIGATE",
|
type: "NAVIGATE",
|
||||||
@ -486,7 +500,7 @@ export default class Profile extends React.Component {
|
|||||||
<UserEntry
|
<UserEntry
|
||||||
key={relation.id}
|
key={relation.id}
|
||||||
user={relation.owner}
|
user={relation.owner}
|
||||||
button={button}
|
button={this.props.external ? null : button} //FOR TARA: clicking on a following/follower person errors if you are in the external view. I recommend making it check if this.props.external, in which case do a link instead (wrap it with an <a href={urlHere}> tag). See SlatePreviewBlocks for an example if you need one
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.props.onAction({
|
this.props.onAction({
|
||||||
type: "NAVIGATE",
|
type: "NAVIGATE",
|
||||||
@ -499,12 +513,37 @@ export default class Profile extends React.Component {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let total = 0;
|
//FOR TARA: I wanted to introduce you to the "reduce" function. It basically walks through all the items in an array and reduces it down to one "summary" value
|
||||||
for (let slate of data.slates) {
|
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
|
||||||
total += slate.data.objects.length;
|
//This allows you to quickly take the sum of the lengths of the objects in each slate for example, or get the maximum value in an array
|
||||||
}
|
//It isn't necessary to use since you can usually use a for loop instead, but good to know in case you encounter it later
|
||||||
|
// let total = 0;
|
||||||
|
// for (let slate of data.slates) {
|
||||||
|
// total += slate.data.objects.length;
|
||||||
|
// }
|
||||||
|
let total = data.slates.reduce((total, slate) => {
|
||||||
|
return total + slate.data?.objects?.length || 0; //FOR TARA: should use optional chaining and add a default value of 0 in case there are some slates where slate.data or slate.data.objects is null
|
||||||
|
}, 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<GlobalCarousel
|
||||||
|
carouselType="data"
|
||||||
|
onUpdateViewer={this.props.onUpdateViewer}
|
||||||
|
resources={this.props.resources}
|
||||||
|
viewer={this.props.viewer}
|
||||||
|
objects={
|
||||||
|
this.state.fileTab === 0
|
||||||
|
? this.props.creator.library[0].children
|
||||||
|
: this.state.fileTab === 1
|
||||||
|
? this.state.publicFiles
|
||||||
|
: this.state.pseudoPrivateFiles
|
||||||
|
}
|
||||||
|
isOwner={isOwner}
|
||||||
|
onAction={this.props.onAction}
|
||||||
|
mobile={this.props.mobile}
|
||||||
|
external={this.props.external}
|
||||||
|
/>
|
||||||
<div css={STYLES_PROFILE_BACKGROUND}>
|
<div css={STYLES_PROFILE_BACKGROUND}>
|
||||||
<div css={STYLES_PROFILE_INFO}>
|
<div css={STYLES_PROFILE_INFO}>
|
||||||
<div
|
<div
|
||||||
@ -513,7 +552,29 @@ export default class Profile extends React.Component {
|
|||||||
/>
|
/>
|
||||||
<div css={STYLES_INFO}>
|
<div css={STYLES_INFO}>
|
||||||
<div css={STYLES_NAME}>{Strings.getPresentationName(data)}</div>
|
<div css={STYLES_NAME}>{Strings.getPresentationName(data)}</div>
|
||||||
<div css={STYLES_BUTTON}>{this.props.buttons}</div>
|
{!isOwner && !this.props.external && (
|
||||||
|
<div css={STYLES_BUTTON}>
|
||||||
|
{this.state.isFollowing ? (
|
||||||
|
<ButtonSecondary
|
||||||
|
onClick={(e) => {
|
||||||
|
this.setState({ isFollowing: false });
|
||||||
|
this._handleFollow(e, this.props.creator.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Unfollow
|
||||||
|
</ButtonSecondary>
|
||||||
|
) : (
|
||||||
|
<ButtonPrimary
|
||||||
|
onClick={(e) => {
|
||||||
|
this.setState({ isFollowing: true });
|
||||||
|
this._handleFollow(e, this.props.creator.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Follow
|
||||||
|
</ButtonPrimary>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{data.data.body ? (
|
{data.data.body ? (
|
||||||
<div css={STYLES_DESCRIPTION}>
|
<div css={STYLES_DESCRIPTION}>
|
||||||
<ProcessedText text={data.data.body} />
|
<ProcessedText text={data.data.body} />
|
||||||
@ -522,14 +583,13 @@ export default class Profile extends React.Component {
|
|||||||
<div css={STYLES_STATS}>
|
<div css={STYLES_STATS}>
|
||||||
<div css={STYLES_STAT}>
|
<div css={STYLES_STAT}>
|
||||||
<div style={{ fontFamily: `${Constants.font.text}` }}>
|
<div style={{ fontFamily: `${Constants.font.text}` }}>
|
||||||
{total}{" "}
|
{total} <span style={{ color: `${Constants.system.darkGray}` }}>Files</span>
|
||||||
<span style={{ color: `${Constants.system.darkGray}` }}>Public data</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div css={STYLES_STAT}>
|
<div css={STYLES_STAT}>
|
||||||
<div style={{ fontFamily: `${Constants.font.text}` }}>
|
<div style={{ fontFamily: `${Constants.font.text}` }}>
|
||||||
{data.slates.length}{" "}
|
{data.slates.length}{" "}
|
||||||
<span style={{ color: `${Constants.system.darkGray}` }}>Public slates</span>
|
<span style={{ color: `${Constants.system.darkGray}` }}>Slates</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -558,7 +618,7 @@ export default class Profile extends React.Component {
|
|||||||
<div style={{ display: `flex` }}>
|
<div style={{ display: `flex` }}>
|
||||||
{isOwner && (
|
{isOwner && (
|
||||||
<SecondaryTabGroup
|
<SecondaryTabGroup
|
||||||
tabs={["All files", "Everyone can see", "Link access only"]}
|
tabs={["All files", "Everyone can view", "Link access only"]}
|
||||||
value={this.state.fileTab}
|
value={this.state.fileTab}
|
||||||
onChange={(value) => this.setState({ fileTab: value })}
|
onChange={(value) => this.setState({ fileTab: value })}
|
||||||
style={{ margin: "0 0 24px 0" }}
|
style={{ margin: "0 0 24px 0" }}
|
||||||
@ -574,6 +634,8 @@ 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>
|
||||||
|
{/* FOR TARA: I want you to see how you can compress these following lines 625-713. There is a lot of repeated code here and you don't need to be restating DataView and EmptyState so many times.
|
||||||
|
You could just change what is passed into items for DataView (or even make a variable named items at the render method, assign it to the right thing, then just pass it into items) and what is displayed in the text for EmptyState */}
|
||||||
{isOwner ? (
|
{isOwner ? (
|
||||||
<div>
|
<div>
|
||||||
{this.state.fileTab === 0 ? (
|
{this.state.fileTab === 0 ? (
|
||||||
@ -655,7 +717,9 @@ export default class Profile extends React.Component {
|
|||||||
) : (
|
) : (
|
||||||
<EmptyState>
|
<EmptyState>
|
||||||
<FileTypeGroup />
|
<FileTypeGroup />
|
||||||
<div style={{ marginTop: 24 }}>Drag and drop files into Slate to upload</div>
|
<div style={{ marginTop: 24 }}>
|
||||||
|
This user does not have any public files yet
|
||||||
|
</div>
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -665,7 +729,7 @@ export default class Profile extends React.Component {
|
|||||||
{this.state.tab === 1 ? (
|
{this.state.tab === 1 ? (
|
||||||
<div>
|
<div>
|
||||||
<SecondaryTabGroup
|
<SecondaryTabGroup
|
||||||
tabs={["Public Slates", "Following Slates"]}
|
tabs={["Slates", "Following"]}
|
||||||
value={this.state.slateTab}
|
value={this.state.slateTab}
|
||||||
onChange={(value) => this.setState({ slateTab: value })}
|
onChange={(value) => this.setState({ slateTab: value })}
|
||||||
style={{ margin: "0 0 24px 0" }}
|
style={{ margin: "0 0 24px 0" }}
|
||||||
@ -675,7 +739,7 @@ export default class Profile extends React.Component {
|
|||||||
{this.state.publicSlates && this.state.publicSlates.length ? (
|
{this.state.publicSlates && this.state.publicSlates.length ? (
|
||||||
<SlatePreviewBlocks
|
<SlatePreviewBlocks
|
||||||
isOwner={this.props.isOwner}
|
isOwner={this.props.isOwner}
|
||||||
external={this.props.onAction ? false : true}
|
external={this.props.external}
|
||||||
slates={this.state.publicSlates}
|
slates={this.state.publicSlates}
|
||||||
username={data.username}
|
username={data.username}
|
||||||
onAction={this.props.onAction}
|
onAction={this.props.onAction}
|
||||||
@ -683,24 +747,24 @@ export default class Profile extends React.Component {
|
|||||||
) : (
|
) : (
|
||||||
<EmptyState>
|
<EmptyState>
|
||||||
<SVG.Slate height="24px" style={{ marginBottom: 24 }} />
|
<SVG.Slate height="24px" style={{ marginBottom: 24 }} />
|
||||||
There aren't any public slates yet.
|
This user does not have any public slates yet
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{this.state.slateTab === 1 ? (
|
{this.state.slateTab === 1 ? (
|
||||||
<div>
|
<div>
|
||||||
{this.state.followingSlates && this.state.followingSlates.length ? (
|
{followingSlates?.length ? ( //FOR TARA: with the optional chaining (see the link I sent you), you can replace "followingSlates && followingSlates.length" with just followingSlates?.length
|
||||||
<SlatePreviewBlocks
|
<SlatePreviewBlocks
|
||||||
isOwner={false}
|
isOwner={false}
|
||||||
external={this.props.onAction ? false : true}
|
external={this.props.external}
|
||||||
slates={this.state.followingSlates}
|
slates={followingSlates}
|
||||||
onAction={this.props.onAction}
|
onAction={this.props.onAction}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<EmptyState>
|
<EmptyState>
|
||||||
<SVG.Slate height="24px" style={{ marginBottom: 24 }} />
|
<SVG.Slate height="24px" style={{ marginBottom: 24 }} />
|
||||||
There aren't any following slates yet.
|
This user is not following any slates yet
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -722,7 +786,7 @@ export default class Profile extends React.Component {
|
|||||||
) : (
|
) : (
|
||||||
<EmptyState>
|
<EmptyState>
|
||||||
<SVG.Users height="24px" style={{ marginBottom: 24 }} />
|
<SVG.Users height="24px" style={{ marginBottom: 24 }} />
|
||||||
There isn't any following yet.
|
This user is not following anyone yet
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -734,7 +798,7 @@ export default class Profile extends React.Component {
|
|||||||
) : (
|
) : (
|
||||||
<EmptyState>
|
<EmptyState>
|
||||||
<SVG.Users height="24px" style={{ marginBottom: 24 }} />
|
<SVG.Users height="24px" style={{ marginBottom: 24 }} />
|
||||||
There aren't any followers yet.
|
This user does not have any followers yet
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,6 +10,7 @@ import * as Events from "~/common/custom-events";
|
|||||||
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
|
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
|
||||||
import CTATransition from "~/components/core/CTATransition";
|
import CTATransition from "~/components/core/CTATransition";
|
||||||
|
|
||||||
|
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
|
||||||
import { CheckBox } from "~/components/system/components/CheckBox";
|
import { CheckBox } from "~/components/system/components/CheckBox";
|
||||||
import { css } from "@emotion/react";
|
import { css } from "@emotion/react";
|
||||||
import { LoaderSpinner } from "~/components/system/components/Loaders";
|
import { LoaderSpinner } from "~/components/system/components/Loaders";
|
||||||
@ -1105,6 +1106,17 @@ export class SlateLayout extends React.Component {
|
|||||||
let unit = this.state.unit;
|
let unit = this.state.unit;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<GlobalCarousel
|
||||||
|
carouselType="slate"
|
||||||
|
onUpdateViewer={this.props.onUpdateViewer}
|
||||||
|
viewer={this.props.viewer}
|
||||||
|
objects={this.state.items}
|
||||||
|
current={this.props.current}
|
||||||
|
onAction={this.props.onAction}
|
||||||
|
mobile={this.props.mobile}
|
||||||
|
isOwner={this.props.isOwner}
|
||||||
|
external={this.props.external}
|
||||||
|
/>
|
||||||
{this.props.isOwner ? (
|
{this.props.isOwner ? (
|
||||||
this.state.editing ? (
|
this.state.editing ? (
|
||||||
<div
|
<div
|
||||||
|
@ -11,6 +11,7 @@ import { Alert } from "~/components/core/Alert";
|
|||||||
import CarouselSidebarSlate from "~/components/core/CarouselSidebarSlate";
|
import CarouselSidebarSlate from "~/components/core/CarouselSidebarSlate";
|
||||||
import CarouselSidebarData from "~/components/core/CarouselSidebarData";
|
import CarouselSidebarData from "~/components/core/CarouselSidebarData";
|
||||||
import SlateMediaObject from "~/components/core/SlateMediaObject";
|
import SlateMediaObject from "~/components/core/SlateMediaObject";
|
||||||
|
import { CompressedPixelFormat } from "three";
|
||||||
|
|
||||||
const STYLES_ROOT = css`
|
const STYLES_ROOT = css`
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@ -124,6 +125,12 @@ export class GlobalCarousel extends React.Component {
|
|||||||
window.removeEventListener("slate-global-close-carousel", this._handleClose);
|
window.removeEventListener("slate-global-close-carousel", this._handleClose);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
componentDidUpdate = (prevProps) => {
|
||||||
|
if (this.state.index >= (this.props.objects?.length || 0)) {
|
||||||
|
this._handleClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
_handleKeyDown = (e) => {
|
_handleKeyDown = (e) => {
|
||||||
const inputs = document.querySelectorAll("input");
|
const inputs = document.querySelectorAll("input");
|
||||||
for (let i = 0; i < inputs.length; i++) {
|
for (let i = 0; i < inputs.length; i++) {
|
||||||
@ -155,20 +162,16 @@ export class GlobalCarousel extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handleOpen = (e) => {
|
_handleOpen = (e) => {
|
||||||
let carouselType =
|
if (e.detail.index < 0 || e.detail.index >= this.props.objects.length) {
|
||||||
!this.props.current ||
|
return;
|
||||||
(this.props.current &&
|
}
|
||||||
(this.props.current.decorator === "FOLDER" || this.props.current.decorator === "ACTIVITY"))
|
|
||||||
? "data"
|
|
||||||
: "slate";
|
|
||||||
this.setState({
|
this.setState({
|
||||||
carouselType: carouselType,
|
|
||||||
visible: true,
|
visible: true,
|
||||||
index: e.detail.index || 0,
|
index: e.detail.index || 0,
|
||||||
baseURL: window.location.pathname,
|
baseURL: window.location.pathname,
|
||||||
});
|
});
|
||||||
if (carouselType === "slate" && this.props.current.data?.objects) {
|
if (this.props.carouselType === "slate") {
|
||||||
const data = this.props.current.data.objects[e.detail.index];
|
const data = this.props.objects[e.detail.index];
|
||||||
window.history.replaceState(
|
window.history.replaceState(
|
||||||
{ ...window.history.state, cid: data.cid },
|
{ ...window.history.state, cid: data.cid },
|
||||||
null,
|
null,
|
||||||
@ -193,31 +196,13 @@ export class GlobalCarousel extends React.Component {
|
|||||||
|
|
||||||
_handleNext = () => {
|
_handleNext = () => {
|
||||||
let index = this.state.index + 1;
|
let index = this.state.index + 1;
|
||||||
if (
|
if (index >= this.props.objects.length) {
|
||||||
this.state.carouselType === "slate" &&
|
index = 0;
|
||||||
this.props.current.data &&
|
|
||||||
this.props.current.data.objects
|
|
||||||
) {
|
|
||||||
if (index >= this.props.current.data.objects.length) {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
this.state.carouselType === "data" &&
|
|
||||||
this.props.viewer &&
|
|
||||||
this.props.viewer.library
|
|
||||||
) {
|
|
||||||
if (index >= this.props.viewer.library[0].children.length) {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.setState({ index });
|
this.setState({ index });
|
||||||
|
|
||||||
if (
|
if (this.props.carouselType === "slate" && this.state.baseURL) {
|
||||||
this.state.carouselType === "slate" &&
|
const data = this.props.objects[index];
|
||||||
this.state.baseURL &&
|
|
||||||
this.props.current.data?.objects
|
|
||||||
) {
|
|
||||||
const data = this.props.current.data.objects[index];
|
|
||||||
window.history.replaceState(
|
window.history.replaceState(
|
||||||
{ ...window.history.state, cid: data.cid },
|
{ ...window.history.state, cid: data.cid },
|
||||||
"",
|
"",
|
||||||
@ -229,28 +214,12 @@ export class GlobalCarousel extends React.Component {
|
|||||||
_handlePrevious = () => {
|
_handlePrevious = () => {
|
||||||
let index = this.state.index - 1;
|
let index = this.state.index - 1;
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
if (
|
index = this.props.objects.length - 1;
|
||||||
this.state.carouselType === "slate" &&
|
|
||||||
this.props.current.data &&
|
|
||||||
this.props.current.data.objects
|
|
||||||
) {
|
|
||||||
index = this.props.current.data.objects.length - 1;
|
|
||||||
} else if (
|
|
||||||
this.state.carouselType === "data" &&
|
|
||||||
this.props.viewer &&
|
|
||||||
this.props.viewer.library
|
|
||||||
) {
|
|
||||||
index = this.props.viewer.library[0].children.length - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.setState({ index });
|
this.setState({ index });
|
||||||
|
|
||||||
if (
|
if (this.props.carouselType === "slate" && this.state.baseURL) {
|
||||||
this.state.carouselType === "slate" &&
|
const data = this.props.objects[index];
|
||||||
this.state.baseURL &&
|
|
||||||
this.props.current.data?.objects
|
|
||||||
) {
|
|
||||||
const data = this.props.current.data.objects[index];
|
|
||||||
window.history.replaceState(
|
window.history.replaceState(
|
||||||
{ ...window.history.state, cid: data.cid },
|
{ ...window.history.state, cid: data.cid },
|
||||||
"",
|
"",
|
||||||
@ -260,9 +229,9 @@ export class GlobalCarousel extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handleSave = async (details, index) => {
|
_handleSave = async (details, index) => {
|
||||||
if (this.state.carouselType === "slate") {
|
let objects = this.props.objects;
|
||||||
if (this.props.viewer.id !== this.props.current.data.ownerId || this.props.external) return;
|
if (!this.props.isOwner || this.props.external) return;
|
||||||
let objects = this.props.current.data.objects;
|
if (this.props.carouselType === "slate") {
|
||||||
objects[index] = { ...objects[index], ...details };
|
objects[index] = { ...objects[index], ...details };
|
||||||
const response = await Actions.updateSlate({
|
const response = await Actions.updateSlate({
|
||||||
id: this.props.current.id,
|
id: this.props.current.id,
|
||||||
@ -270,9 +239,7 @@ export class GlobalCarousel extends React.Component {
|
|||||||
});
|
});
|
||||||
Events.hasError(response);
|
Events.hasError(response);
|
||||||
}
|
}
|
||||||
if (this.state.carouselType === "data") {
|
if (this.props.carouselType === "data") {
|
||||||
if (this.props.external) return;
|
|
||||||
let objects = this.props.viewer.library[0].children;
|
|
||||||
objects[index] = { ...objects[index], ...details };
|
objects[index] = { ...objects[index], ...details };
|
||||||
const response = await Actions.updateData({
|
const response = await Actions.updateData({
|
||||||
id: this.props.viewer.id,
|
id: this.props.viewer.id,
|
||||||
@ -283,35 +250,16 @@ export class GlobalCarousel extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.state.visible || !this.state.carouselType || this.state.index < 0) {
|
if (!this.state.visible || !this.props.carouselType || this.state.index < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let data;
|
let data = this.props.objects[this.state.index];
|
||||||
let isOwner;
|
let isOwner = this.props.isOwner;
|
||||||
let isRepost;
|
let isRepost;
|
||||||
if (
|
if (this.props.carouselType === "slate") {
|
||||||
this.state.carouselType === "slate" &&
|
|
||||||
this.props.current?.data?.objects?.length &&
|
|
||||||
this.state.index < this.props.current.data.objects.length
|
|
||||||
) {
|
|
||||||
data = this.props.current.data.objects[this.state.index];
|
|
||||||
data.cid = Strings.urlToCid(data.url);
|
|
||||||
isRepost = this.props.external ? false : this.props.current.data.ownerId !== data.ownerId;
|
isRepost = this.props.external ? false : this.props.current.data.ownerId !== data.ownerId;
|
||||||
isOwner = this.props.external
|
} else if (this.props.carouselType === "data") {
|
||||||
? false
|
|
||||||
: this.props.viewer.id === this.props.current.data.ownerId;
|
|
||||||
} else if (
|
|
||||||
this.state.carouselType === "data" &&
|
|
||||||
this.props.viewer?.library[0]?.children?.length &&
|
|
||||||
this.state.index < this.props.viewer.library[0].children.length
|
|
||||||
) {
|
|
||||||
data = this.props.viewer.library[0].children[this.state.index];
|
|
||||||
data.url = Strings.getCIDGatewayURL(data.cid);
|
data.url = Strings.getCIDGatewayURL(data.cid);
|
||||||
isOwner = this.props.external ? false : true;
|
|
||||||
}
|
|
||||||
if (!data) {
|
|
||||||
this._handleClose();
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
let slide = <SlateMediaObject data={data} />;
|
let slide = <SlateMediaObject data={data} />;
|
||||||
return (
|
return (
|
||||||
@ -383,14 +331,14 @@ export class GlobalCarousel extends React.Component {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span css={STYLES_MOBILE_HIDDEN}>
|
<span css={STYLES_MOBILE_HIDDEN}>
|
||||||
{this.state.carouselType === "data" ? (
|
{this.props.carouselType === "data" ? (
|
||||||
<CarouselSidebarData
|
<CarouselSidebarData
|
||||||
viewer={this.props.viewer}
|
viewer={this.props.viewer}
|
||||||
display={this.state.showSidebar ? "block" : "none"}
|
display={this.state.showSidebar ? "block" : "none"}
|
||||||
onUpdateViewer={this.props.onUpdateViewer}
|
onUpdateViewer={this.props.onUpdateViewer}
|
||||||
onClose={this._handleClose}
|
onClose={this._handleClose}
|
||||||
key={data.id}
|
key={data.id}
|
||||||
slates={this.props.slates}
|
slates={this.props.viewer?.slates || []}
|
||||||
onAction={this.props.onAction}
|
onAction={this.props.onAction}
|
||||||
resources={this.props.resources}
|
resources={this.props.resources}
|
||||||
data={data}
|
data={data}
|
||||||
@ -407,7 +355,7 @@ export class GlobalCarousel extends React.Component {
|
|||||||
onUpdateViewer={this.props.onUpdateViewer}
|
onUpdateViewer={this.props.onUpdateViewer}
|
||||||
current={this.props.current}
|
current={this.props.current}
|
||||||
key={data.id}
|
key={data.id}
|
||||||
slates={this.props.slates}
|
slates={this.props.viewer?.slates || []}
|
||||||
onClose={this._handleClose}
|
onClose={this._handleClose}
|
||||||
onAction={this.props.onAction}
|
onAction={this.props.onAction}
|
||||||
data={data}
|
data={data}
|
||||||
@ -416,7 +364,6 @@ export class GlobalCarousel extends React.Component {
|
|||||||
isOwner={isOwner}
|
isOwner={isOwner}
|
||||||
isRepost={isRepost}
|
isRepost={isRepost}
|
||||||
index={this.state.index}
|
index={this.state.index}
|
||||||
external={this.props.external}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
@ -35,7 +35,6 @@ export default class ProfilePage extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
console.log(this.props.creator);
|
|
||||||
const title = this.props.creator ? `${this.props.creator.username}` : "404";
|
const title = this.props.creator ? `${this.props.creator.username}` : "404";
|
||||||
const url = `https://slate.host/${title}`;
|
const url = `https://slate.host/${title}`;
|
||||||
const description = this.props.creator.data.body;
|
const description = this.props.creator.data.body;
|
||||||
@ -52,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} />
|
<Profile {...this.props} buttons={buttons} external />
|
||||||
</div>
|
</div>
|
||||||
{this.state.visible && (
|
{this.state.visible && (
|
||||||
<div>
|
<div>
|
||||||
|
@ -13,7 +13,6 @@ import { ViewAllButton } from "~/components/core/ViewAll";
|
|||||||
import { SlateLayout } from "~/components/core/SlateLayout";
|
import { SlateLayout } from "~/components/core/SlateLayout";
|
||||||
import { SlateLayoutMobile } from "~/components/core/SlateLayoutMobile";
|
import { SlateLayoutMobile } from "~/components/core/SlateLayoutMobile";
|
||||||
import { GlobalModal } from "~/components/system/components/GlobalModal";
|
import { GlobalModal } from "~/components/system/components/GlobalModal";
|
||||||
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
|
|
||||||
|
|
||||||
import ProcessedText from "~/components/core/ProcessedText";
|
import ProcessedText from "~/components/core/ProcessedText";
|
||||||
import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper";
|
import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper";
|
||||||
@ -317,6 +316,7 @@ export default class SlatePage extends React.Component {
|
|||||||
items={objects}
|
items={objects}
|
||||||
fileNames={layouts && layouts.ver === "2.0" ? layouts.fileNames : false}
|
fileNames={layouts && layouts.ver === "2.0" ? layouts.fileNames : false}
|
||||||
onSelect={this._handleSelect}
|
onSelect={this._handleSelect}
|
||||||
|
external
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<SlateLayout
|
<SlateLayout
|
||||||
@ -335,7 +335,6 @@ export default class SlatePage extends React.Component {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<GlobalCarousel external current={this.props.slate} mobile={this.props.mobile} />
|
|
||||||
<GlobalModal />
|
<GlobalModal />
|
||||||
{this.state.visible && (
|
{this.state.visible && (
|
||||||
<div>
|
<div>
|
||||||
|
@ -4,6 +4,7 @@ import * as SVG from "~/common/svg";
|
|||||||
import { ButtonPrimary } from "~/components/system/components/Buttons";
|
import { ButtonPrimary } from "~/components/system/components/Buttons";
|
||||||
import { FileTypeGroup } from "~/components/core/FileTypeIcon";
|
import { FileTypeGroup } from "~/components/core/FileTypeIcon";
|
||||||
import { PrimaryTabGroup, SecondaryTabGroup } from "~/components/core/TabGroup";
|
import { PrimaryTabGroup, SecondaryTabGroup } from "~/components/core/TabGroup";
|
||||||
|
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
|
||||||
|
|
||||||
import ScenePage from "~/components/core/ScenePage";
|
import ScenePage from "~/components/core/ScenePage";
|
||||||
import DataView from "~/components/core/DataView";
|
import DataView from "~/components/core/DataView";
|
||||||
@ -45,6 +46,16 @@ export default class SceneFilesFolder extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<GlobalCarousel
|
||||||
|
carouselType="data"
|
||||||
|
onUpdateViewer={this.props.onUpdateViewer}
|
||||||
|
resources={this.props.resources}
|
||||||
|
viewer={this.props.viewer}
|
||||||
|
objects={this.props.viewer?.library[0]?.children || []}
|
||||||
|
onAction={this.props.onAction}
|
||||||
|
mobile={this.props.mobile}
|
||||||
|
isOwner={true}
|
||||||
|
/>
|
||||||
<DataMeter
|
<DataMeter
|
||||||
stats={this.props.viewer.stats}
|
stats={this.props.viewer.stats}
|
||||||
style={{ marginBottom: 64 }}
|
style={{ marginBottom: 64 }}
|
||||||
|
@ -3,19 +3,12 @@ import * as Actions from "~/common/actions";
|
|||||||
import * as SVG from "~/common/svg";
|
import * as SVG from "~/common/svg";
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
import { css } from "@emotion/react";
|
||||||
import { ButtonPrimary, ButtonSecondary } from "~/components/system/components/Buttons";
|
|
||||||
import { LoaderSpinner } from "~/components/system/components/Loaders";
|
import { LoaderSpinner } from "~/components/system/components/Loaders";
|
||||||
|
|
||||||
import ScenePage from "~/components/core/ScenePage";
|
import ScenePage from "~/components/core/ScenePage";
|
||||||
import Profile from "~/components/core/Profile";
|
import Profile from "~/components/core/Profile";
|
||||||
import EmptyState from "~/components/core/EmptyState";
|
import EmptyState from "~/components/core/EmptyState";
|
||||||
|
|
||||||
const STYLES_BUTTONS = css`
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STYLES_LOADER = css`
|
const STYLES_LOADER = css`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -75,7 +68,7 @@ export default class SceneProfile extends React.Component {
|
|||||||
window.history.replaceState(window.history.state, "A slate user", `/${targetUser.username}`);
|
window.history.replaceState(window.history.state, "A slate user", `/${targetUser.username}`);
|
||||||
|
|
||||||
this.props.onUpdateData({ data: targetUser });
|
this.props.onUpdateData({ data: targetUser });
|
||||||
this.setState({ profile: targetUser });
|
this.setState({ profile: targetUser }); //martina: keep this here? or use the data itself rather than using this?
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -98,58 +91,15 @@ export default class SceneProfile extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ProfilePage {...this.props} data={this.state.profile} />;
|
//FOR TARA: this is the change that'll allow it to update "automatically" if you're viewing your own profile and make changes
|
||||||
}
|
//if you are viewing your own profile (aka this.state.profile.id === this.props.viewer.id), it'll set it to viewer directly, rather than a stale copy of viewer
|
||||||
}
|
|
||||||
|
|
||||||
class ProfilePage 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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_handleFollow = async () => {
|
|
||||||
this.setState({ isFollowing: !this.state.isFollowing });
|
|
||||||
await Actions.createSubscription({
|
|
||||||
userId: this.props.data.id,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let buttons = (
|
|
||||||
<div css={STYLES_BUTTONS}>
|
|
||||||
{this.state.isFollowing ? (
|
|
||||||
<ButtonSecondary onClick={this._handleFollow}>Unfollow</ButtonSecondary>
|
|
||||||
) : (
|
|
||||||
<ButtonPrimary onClick={this._handleFollow}>Follow</ButtonPrimary>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<ScenePage style={{ padding: `0` }}>
|
<Profile
|
||||||
<Profile
|
{...this.props}
|
||||||
{...this.props}
|
creator={
|
||||||
onAction={this.props.onAction}
|
this.state.profile.id === this.props.viewer.id ? this.props.viewer : this.state.profile
|
||||||
creator={this.props.data}
|
}
|
||||||
sceneId={this.props.sceneId}
|
/>
|
||||||
buttons={this.props.viewer.username === this.props.data.username ? null : buttons}
|
|
||||||
isOwner={this.props.viewer.username === this.props.data.username}
|
|
||||||
/>
|
|
||||||
</ScenePage>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user