added carousel to profiles and fixed not updating bug

This commit is contained in:
Martina 2021-01-16 17:53:02 -08:00
parent 7f4f6a4b04
commit c4301e74b8
9 changed files with 282 additions and 295 deletions

View File

@ -52,7 +52,6 @@ import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper";
import { GlobalModal } from "~/components/system/components/GlobalModal";
import { OnboardingModal } from "~/components/core/OnboardingModal";
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
import { SearchModal } from "~/components/core/SearchModal";
import { Alert } from "~/components/core/Alert";
import { announcements } from "~/components/core/OnboardingModal";
@ -690,15 +689,6 @@ export default class ApplicationPage extends React.Component {
>
{scene}
</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 />
<SearchModal
viewer={this.state.viewer}

View File

@ -82,6 +82,7 @@ const STYLES_DISMISS_BOX = css`
`;
const STYLES_META = css`
text-align: start;
padding: 14px 0px 8px 0px;
overflow-wrap: break-word;
`;
@ -343,6 +344,7 @@ export default class CarouselSidebarData extends React.Component {
};
_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`;
if (!window.confirm(message)) {
return;
@ -384,7 +386,6 @@ export default class CarouselSidebarData extends React.Component {
const isVisible = this.state.inPublicSlates || this.state.isPublic;
let selected = this.state.selected;
if (this.state.inPublicSlates) {
console.log("in public slates");
const slateIds = Object.entries(this.state.selected)
.filter((entry) => entry[1])
.map((entry) => entry[0]);
@ -410,7 +411,6 @@ export default class CarouselSidebarData extends React.Component {
public: !isVisible,
},
});
console.log(response);
if (isVisible) {
this.setState({ inPublicSlates: false, isPublic: false, selected });
} else {
@ -445,7 +445,10 @@ export default class CarouselSidebarData extends React.Component {
/>
</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}
</span>
)}
@ -462,37 +465,45 @@ export default class CarouselSidebarData extends React.Component {
</div>
</div>
<div css={STYLES_ACTIONS}>
<div css={STYLES_ACTION} onClick={() => this._handleCopy(cid, "cidCopying")}>
<SVG.CopyAndPaste height="24px" />
<span style={{ marginLeft: 16 }}>
{this.state.loading === "cidCopying" ? "Copied!" : "Copy file CID"}
</span>
</div>
{this.props.isOwner ? (
<div css={STYLES_ACTION} onClick={() => this._handleCopy(cid, "cidCopying")}>
<SVG.CopyAndPaste height="24px" />
<span style={{ marginLeft: 16 }}>
{this.state.loading === "cidCopying" ? "Copied!" : "Copy file CID"}
</span>
</div>
) : null}
<div css={STYLES_ACTION} onClick={() => this._handleCopy(url, "gatewayUrlCopying")}>
<SVG.Data height="24px" />
<span style={{ marginLeft: 16 }}>
{this.state.loading === "gatewayUrlCopying" ? "Copied!" : "Copy gateway URL"}
{this.state.loading === "gatewayUrlCopying" ? "Copied!" : "Copy external URL"}
</span>
</div>
<div css={STYLES_ACTION} onClick={this._handleDownload}>
<SVG.Download height="24px" />
<span style={{ marginLeft: 16 }}>Download</span>
</div>
<div css={STYLES_ACTION} onClick={() => this._handleDelete(cid)}>
<SVG.Trash height="24px" />
<span style={{ marginLeft: 16 }}>Delete</span>
</div>
{this.props.isOwner ? (
<div css={STYLES_ACTION} onClick={() => this._handleDelete(cid)}>
<SVG.Trash height="24px" />
<span style={{ marginLeft: 16 }}>Delete</span>
</div>
) : null}
</div>
<div css={STYLES_SECTION_HEADER}>Connected Slates</div>
<SlatePicker
dark
slates={this.props.slates}
onCreateSlate={this._handleCreateSlate}
selectedColor={Constants.system.white}
files={[this.props.data]}
selected={this.state.selected}
onAdd={this._handleAdd}
/>
{this.props.external ? null : (
<React.Fragment>
<div css={STYLES_SECTION_HEADER}>Connected Slates</div>
<SlatePicker
dark
slates={this.props.slates}
onCreateSlate={this._handleCreateSlate}
selectedColor={Constants.system.white}
files={[this.props.data]}
selected={this.state.selected}
onAdd={this._handleAdd}
/>
</React.Fragment>
)}
{type && Validations.isPreviewableImage(type) ? null : (
<div>
<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 css={STYLES_SECTION_HEADER} style={{ margin: "48px 0px 8px 0px" }}>
Visibility
</div>
<div
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
margin: "16px 0 16px 0",
}}
>
<div style={{ color: Constants.system.darkGray, lineHeight: "1.5" }}>
{isVisible ? "Everyone" : "Link only"}
</div>
<Toggle dark active={isVisible} onChange={this._handleToggleVisibility} />
</div>
<div style={{ color: Constants.system.darkGray, marginTop: 8 }}>
{isVisible
? "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>
{this.props.isOwner ? (
<React.Fragment>
<div css={STYLES_SECTION_HEADER} style={{ margin: "48px 0px 8px 0px" }}>
Visibility
</div>
<div
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
margin: "16px 0 16px 0",
}}
>
<div style={{ color: Constants.system.darkGray, lineHeight: "1.5" }}>
{isVisible ? "Everyone" : "Link only"}
</div>
<Toggle dark active={isVisible} onChange={this._handleToggleVisibility} />
</div>
<div style={{ color: Constants.system.darkGray, marginTop: 8 }}>
{isVisible
? "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
css={STYLES_HIDDEN}
ref={(c) => {

View File

@ -4,7 +4,14 @@ import * as Strings from "~/common/strings";
import * as SVG from "~/common/svg";
import * as Actions from "~/common/actions";
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
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 SlatePreviewBlocks from "~/components/core/SlatePreviewBlock";
@ -12,12 +19,6 @@ import CTATransition from "~/components/core/CTATransition";
import DataView from "~/components/core/DataView";
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`
background-color: ${Constants.system.white};
width: 100%;
@ -60,7 +61,8 @@ const STYLES_INFO = 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-position: 50% 50%;
width: 120px;
@ -108,8 +110,8 @@ const STYLES_STATS = css`
`;
const STYLES_STAT = css`
margin-right: 8px;
width: 112px;
margin: 0px 12px;
${"" /* width: 112px; */}
flex-shrink: 0;
`;
@ -233,70 +235,53 @@ export default class Profile extends React.Component {
peerTab: 0,
copyValue: "",
contextMenu: null,
followingSlates: [],
publicSlates: [],
publicFiles: [],
pseudoPrivateFiles: [],
};
_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,
});
isFollowing: this.props.external
? false
: !!this.props.viewer.subscriptions.filter((entry) => {
return entry.target_user_id === this.props.data.id;
}).length,
//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
};
componentDidMount = async () => {
await this.filterByVisibility();
await this.fetchUsername();
};
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();
}
};
fetchUsername = async () => {
let followingSlates = [];
let subscriptions = this.props.creator.subscriptions ? this.props.creator.subscriptions : null;
for (let subscription of subscriptions) {
if (subscription.slate != null) {
followingSlates.push(subscription.slate);
}
}
//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
//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
// fetchUsername = async () => {
// let followingSlates = [];
// let subscriptions = this.props.creator.subscriptions ? this.props.creator.subscriptions : [];
// for (let subscription of subscriptions) {
// if (subscription.slate != null) {
// followingSlates.push(subscription.slate);
// }
// }
for (let followingSlate of followingSlates) {
let id = { id: followingSlate.data.ownerId };
let slateOwner = await Actions.getSerializedProfile(id);
followingSlate.username = slateOwner.data?.username;
}
// for (let followingSlate of followingSlates) {
// let id = { id: followingSlate.data.ownerId };
// 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;
// }
this.setState({ followingSlates: followingSlates });
};
// this.setState({ followingSlates: followingSlates });
// };
filterByVisibility = async () => {
let publicFiles = [];
@ -334,24 +319,53 @@ export default class Profile extends React.Component {
publicFiles: publicFiles,
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() {
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 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
.filter((relation) => {
@ -415,7 +429,7 @@ export default class Profile extends React.Component {
<UserEntry
key={relation.id}
user={relation.user}
button={button}
button={this.props.external ? null : button}
onClick={() => {
this.props.onAction({
type: "NAVIGATE",
@ -486,7 +500,7 @@ export default class Profile extends React.Component {
<UserEntry
key={relation.id}
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={() => {
this.props.onAction({
type: "NAVIGATE",
@ -499,12 +513,37 @@ export default class Profile extends React.Component {
);
});
let total = 0;
for (let slate of data.slates) {
total += slate.data.objects.length;
}
//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
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
//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 (
<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_INFO}>
<div
@ -513,7 +552,29 @@ export default class Profile extends React.Component {
/>
<div css={STYLES_INFO}>
<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 ? (
<div css={STYLES_DESCRIPTION}>
<ProcessedText text={data.data.body} />
@ -522,14 +583,13 @@ export default class Profile extends React.Component {
<div css={STYLES_STATS}>
<div css={STYLES_STAT}>
<div style={{ fontFamily: `${Constants.font.text}` }}>
{total}{" "}
<span style={{ color: `${Constants.system.darkGray}` }}>Public data</span>
{total} <span style={{ color: `${Constants.system.darkGray}` }}>Files</span>
</div>
</div>
<div css={STYLES_STAT}>
<div style={{ fontFamily: `${Constants.font.text}` }}>
{data.slates.length}{" "}
<span style={{ color: `${Constants.system.darkGray}` }}>Public slates</span>
<span style={{ color: `${Constants.system.darkGray}` }}>Slates</span>
</div>
</div>
</div>
@ -558,7 +618,7 @@ export default class Profile extends React.Component {
<div style={{ display: `flex` }}>
{isOwner && (
<SecondaryTabGroup
tabs={["All files", "Everyone can see", "Link access only"]}
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" }}
@ -574,6 +634,8 @@ export default class Profile extends React.Component {
style={{ margin: "0 0 24px 0", justifyContent: "flex-end" }}
/>
</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 ? (
<div>
{this.state.fileTab === 0 ? (
@ -655,7 +717,9 @@ export default class Profile extends React.Component {
) : (
<EmptyState>
<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>
)}
</div>
@ -665,7 +729,7 @@ export default class Profile extends React.Component {
{this.state.tab === 1 ? (
<div>
<SecondaryTabGroup
tabs={["Public Slates", "Following Slates"]}
tabs={["Slates", "Following"]}
value={this.state.slateTab}
onChange={(value) => this.setState({ slateTab: value })}
style={{ margin: "0 0 24px 0" }}
@ -675,7 +739,7 @@ export default class Profile extends React.Component {
{this.state.publicSlates && this.state.publicSlates.length ? (
<SlatePreviewBlocks
isOwner={this.props.isOwner}
external={this.props.onAction ? false : true}
external={this.props.external}
slates={this.state.publicSlates}
username={data.username}
onAction={this.props.onAction}
@ -683,24 +747,24 @@ export default class Profile extends React.Component {
) : (
<EmptyState>
<SVG.Slate height="24px" style={{ marginBottom: 24 }} />
There aren't any public slates yet.
This user does not have any public slates yet
</EmptyState>
)}
</div>
) : null}
{this.state.slateTab === 1 ? (
<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
isOwner={false}
external={this.props.onAction ? false : true}
slates={this.state.followingSlates}
external={this.props.external}
slates={followingSlates}
onAction={this.props.onAction}
/>
) : (
<EmptyState>
<SVG.Slate height="24px" style={{ marginBottom: 24 }} />
There aren't any following slates yet.
This user is not following any slates yet
</EmptyState>
)}
</div>
@ -722,7 +786,7 @@ export default class Profile extends React.Component {
) : (
<EmptyState>
<SVG.Users height="24px" style={{ marginBottom: 24 }} />
There isn't any following yet.
This user is not following anyone yet
</EmptyState>
)}
</div>
@ -734,7 +798,7 @@ export default class Profile extends React.Component {
) : (
<EmptyState>
<SVG.Users height="24px" style={{ marginBottom: 24 }} />
There aren't any followers yet.
This user does not have any followers yet
</EmptyState>
)}
</div>

View File

@ -10,6 +10,7 @@ import * as Events from "~/common/custom-events";
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
import CTATransition from "~/components/core/CTATransition";
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
import { CheckBox } from "~/components/system/components/CheckBox";
import { css } from "@emotion/react";
import { LoaderSpinner } from "~/components/system/components/Loaders";
@ -1105,6 +1106,17 @@ export class SlateLayout extends React.Component {
let unit = this.state.unit;
return (
<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.state.editing ? (
<div

View File

@ -11,6 +11,7 @@ import { Alert } from "~/components/core/Alert";
import CarouselSidebarSlate from "~/components/core/CarouselSidebarSlate";
import CarouselSidebarData from "~/components/core/CarouselSidebarData";
import SlateMediaObject from "~/components/core/SlateMediaObject";
import { CompressedPixelFormat } from "three";
const STYLES_ROOT = css`
position: fixed;
@ -124,6 +125,12 @@ export class GlobalCarousel extends React.Component {
window.removeEventListener("slate-global-close-carousel", this._handleClose);
};
componentDidUpdate = (prevProps) => {
if (this.state.index >= (this.props.objects?.length || 0)) {
this._handleClose();
}
};
_handleKeyDown = (e) => {
const inputs = document.querySelectorAll("input");
for (let i = 0; i < inputs.length; i++) {
@ -155,20 +162,16 @@ export class GlobalCarousel extends React.Component {
};
_handleOpen = (e) => {
let carouselType =
!this.props.current ||
(this.props.current &&
(this.props.current.decorator === "FOLDER" || this.props.current.decorator === "ACTIVITY"))
? "data"
: "slate";
if (e.detail.index < 0 || e.detail.index >= this.props.objects.length) {
return;
}
this.setState({
carouselType: carouselType,
visible: true,
index: e.detail.index || 0,
baseURL: window.location.pathname,
});
if (carouselType === "slate" && this.props.current.data?.objects) {
const data = this.props.current.data.objects[e.detail.index];
if (this.props.carouselType === "slate") {
const data = this.props.objects[e.detail.index];
window.history.replaceState(
{ ...window.history.state, cid: data.cid },
null,
@ -193,31 +196,13 @@ export class GlobalCarousel extends React.Component {
_handleNext = () => {
let index = this.state.index + 1;
if (
this.state.carouselType === "slate" &&
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;
}
if (index >= this.props.objects.length) {
index = 0;
}
this.setState({ index });
if (
this.state.carouselType === "slate" &&
this.state.baseURL &&
this.props.current.data?.objects
) {
const data = this.props.current.data.objects[index];
if (this.props.carouselType === "slate" && this.state.baseURL) {
const data = this.props.objects[index];
window.history.replaceState(
{ ...window.history.state, cid: data.cid },
"",
@ -229,28 +214,12 @@ export class GlobalCarousel extends React.Component {
_handlePrevious = () => {
let index = this.state.index - 1;
if (index < 0) {
if (
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;
}
index = this.props.objects.length - 1;
}
this.setState({ index });
if (
this.state.carouselType === "slate" &&
this.state.baseURL &&
this.props.current.data?.objects
) {
const data = this.props.current.data.objects[index];
if (this.props.carouselType === "slate" && this.state.baseURL) {
const data = this.props.objects[index];
window.history.replaceState(
{ ...window.history.state, cid: data.cid },
"",
@ -260,9 +229,9 @@ export class GlobalCarousel extends React.Component {
};
_handleSave = async (details, index) => {
if (this.state.carouselType === "slate") {
if (this.props.viewer.id !== this.props.current.data.ownerId || this.props.external) return;
let objects = this.props.current.data.objects;
let objects = this.props.objects;
if (!this.props.isOwner || this.props.external) return;
if (this.props.carouselType === "slate") {
objects[index] = { ...objects[index], ...details };
const response = await Actions.updateSlate({
id: this.props.current.id,
@ -270,9 +239,7 @@ export class GlobalCarousel extends React.Component {
});
Events.hasError(response);
}
if (this.state.carouselType === "data") {
if (this.props.external) return;
let objects = this.props.viewer.library[0].children;
if (this.props.carouselType === "data") {
objects[index] = { ...objects[index], ...details };
const response = await Actions.updateData({
id: this.props.viewer.id,
@ -283,35 +250,16 @@ export class GlobalCarousel extends React.Component {
};
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;
}
let data;
let isOwner;
let data = this.props.objects[this.state.index];
let isOwner = this.props.isOwner;
let isRepost;
if (
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);
if (this.props.carouselType === "slate") {
isRepost = this.props.external ? false : this.props.current.data.ownerId !== data.ownerId;
isOwner = this.props.external
? 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];
} else if (this.props.carouselType === "data") {
data.url = Strings.getCIDGatewayURL(data.cid);
isOwner = this.props.external ? false : true;
}
if (!data) {
this._handleClose();
return null;
}
let slide = <SlateMediaObject data={data} />;
return (
@ -383,14 +331,14 @@ export class GlobalCarousel extends React.Component {
</span>
</div>
<span css={STYLES_MOBILE_HIDDEN}>
{this.state.carouselType === "data" ? (
{this.props.carouselType === "data" ? (
<CarouselSidebarData
viewer={this.props.viewer}
display={this.state.showSidebar ? "block" : "none"}
onUpdateViewer={this.props.onUpdateViewer}
onClose={this._handleClose}
key={data.id}
slates={this.props.slates}
slates={this.props.viewer?.slates || []}
onAction={this.props.onAction}
resources={this.props.resources}
data={data}
@ -407,7 +355,7 @@ export class GlobalCarousel extends React.Component {
onUpdateViewer={this.props.onUpdateViewer}
current={this.props.current}
key={data.id}
slates={this.props.slates}
slates={this.props.viewer?.slates || []}
onClose={this._handleClose}
onAction={this.props.onAction}
data={data}
@ -416,7 +364,6 @@ export class GlobalCarousel extends React.Component {
isOwner={isOwner}
isRepost={isRepost}
index={this.state.index}
external={this.props.external}
/>
)}
</span>

View File

@ -35,7 +35,6 @@ export default class ProfilePage extends React.Component {
};
render() {
console.log(this.props.creator);
const title = this.props.creator ? `${this.props.creator.username}` : "404";
const url = `https://slate.host/${title}`;
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}>
<WebsitePrototypeHeader />
<div css={STYLES_ROOT}>
<Profile {...this.props} buttons={buttons} />
<Profile {...this.props} buttons={buttons} external />
</div>
{this.state.visible && (
<div>

View File

@ -13,7 +13,6 @@ import { ViewAllButton } from "~/components/core/ViewAll";
import { SlateLayout } from "~/components/core/SlateLayout";
import { SlateLayoutMobile } from "~/components/core/SlateLayoutMobile";
import { GlobalModal } from "~/components/system/components/GlobalModal";
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
import ProcessedText from "~/components/core/ProcessedText";
import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper";
@ -317,6 +316,7 @@ export default class SlatePage extends React.Component {
items={objects}
fileNames={layouts && layouts.ver === "2.0" ? layouts.fileNames : false}
onSelect={this._handleSelect}
external
/>
) : (
<SlateLayout
@ -335,7 +335,6 @@ export default class SlatePage extends React.Component {
)}
</div>
</div>
<GlobalCarousel external current={this.props.slate} mobile={this.props.mobile} />
<GlobalModal />
{this.state.visible && (
<div>

View File

@ -4,6 +4,7 @@ import * as SVG from "~/common/svg";
import { ButtonPrimary } from "~/components/system/components/Buttons";
import { FileTypeGroup } from "~/components/core/FileTypeIcon";
import { PrimaryTabGroup, SecondaryTabGroup } from "~/components/core/TabGroup";
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
import ScenePage from "~/components/core/ScenePage";
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
stats={this.props.viewer.stats}
style={{ marginBottom: 64 }}

View File

@ -3,19 +3,12 @@ import * as Actions from "~/common/actions";
import * as SVG from "~/common/svg";
import { css } from "@emotion/react";
import { ButtonPrimary, ButtonSecondary } from "~/components/system/components/Buttons";
import { LoaderSpinner } from "~/components/system/components/Loaders";
import ScenePage from "~/components/core/ScenePage";
import Profile from "~/components/core/Profile";
import EmptyState from "~/components/core/EmptyState";
const STYLES_BUTTONS = css`
display: inline-flex;
flex-direction: row;
align-items: center;
`;
const STYLES_LOADER = css`
display: flex;
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}`);
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() {
@ -98,58 +91,15 @@ export default class SceneProfile extends React.Component {
);
}
return <ProfilePage {...this.props} data={this.state.profile} />;
}
}
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>
);
//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
return (
<ScenePage style={{ padding: `0` }}>
<Profile
{...this.props}
onAction={this.props.onAction}
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>
<Profile
{...this.props}
creator={
this.state.profile.id === this.props.viewer.id ? this.props.viewer : this.state.profile
}
/>
);
}
}