mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-25 10:05:02 +03:00
redirecting to in-client page automatic
This commit is contained in:
parent
f24e130791
commit
349fc0f66a
@ -82,6 +82,19 @@ export const getFileExtension = (name) => {
|
|||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createQueryParams = (params) => {
|
||||||
|
let query = "?";
|
||||||
|
let first = true;
|
||||||
|
for (const [key, value] of Object.entries(params)) {
|
||||||
|
if (!first) {
|
||||||
|
query += "&";
|
||||||
|
}
|
||||||
|
query += `${key}=${value}`;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
};
|
||||||
|
|
||||||
export const getCIDFromIPFS = (url) => {
|
export const getCIDFromIPFS = (url) => {
|
||||||
// NOTE(andrew)
|
// NOTE(andrew)
|
||||||
const cid = url.includes("/ipfs/")
|
const cid = url.includes("/ipfs/")
|
||||||
|
@ -129,6 +129,7 @@ export default class ApplicationPage extends React.Component {
|
|||||||
const id = Window.getQueryParameterByName("scene");
|
const id = Window.getQueryParameterByName("scene");
|
||||||
const user = Window.getQueryParameterByName("user");
|
const user = Window.getQueryParameterByName("user");
|
||||||
const slate = Window.getQueryParameterByName("slate");
|
const slate = Window.getQueryParameterByName("slate");
|
||||||
|
const cid = Window.getQueryParameterByName("cid");
|
||||||
|
|
||||||
let wsclient = Websockets.getClient();
|
let wsclient = Websockets.getClient();
|
||||||
if (wsclient) {
|
if (wsclient) {
|
||||||
@ -153,7 +154,7 @@ export default class ApplicationPage extends React.Component {
|
|||||||
|
|
||||||
if (!Strings.isEmpty(id) && this.state.viewer) {
|
if (!Strings.isEmpty(id) && this.state.viewer) {
|
||||||
console.log("redirecting to page");
|
console.log("redirecting to page");
|
||||||
return this._handleNavigateTo({ id, user, slate });
|
return this._handleNavigateTo({ id, user, slate, cid });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +495,6 @@ export default class ApplicationPage extends React.Component {
|
|||||||
|
|
||||||
_handleSidebarLoading = (sidebarLoading) => this.setState({ sidebarLoading });
|
_handleSidebarLoading = (sidebarLoading) => this.setState({ sidebarLoading });
|
||||||
|
|
||||||
//change the naem to hydrate. and use this only upon initial sign in (should be the only time you need it)
|
|
||||||
rehydrate = async (options) => {
|
rehydrate = async (options) => {
|
||||||
const response = await Actions.hydrateAuthenticatedUser();
|
const response = await Actions.hydrateAuthenticatedUser();
|
||||||
|
|
||||||
@ -653,8 +653,6 @@ export default class ApplicationPage extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._handleAction({ type: "NAVIGATE", value: "V1_NAVIGATION_HOME" });
|
|
||||||
|
|
||||||
let unseenAnnouncements = [];
|
let unseenAnnouncements = [];
|
||||||
for (let feature of announcements) {
|
for (let feature of announcements) {
|
||||||
if (!Object.keys(this.state.viewer.onboarding).includes(feature)) {
|
if (!Object.keys(this.state.viewer.onboarding).includes(feature)) {
|
||||||
@ -682,6 +680,17 @@ export default class ApplicationPage extends React.Component {
|
|||||||
if (newAccount) {
|
if (newAccount) {
|
||||||
Actions.updateSearch("create-user");
|
Actions.updateSearch("create-user");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const id = Window.getQueryParameterByName("scene");
|
||||||
|
const user = Window.getQueryParameterByName("user");
|
||||||
|
const slate = Window.getQueryParameterByName("slate");
|
||||||
|
const cid = Window.getQueryParameterByName("cid");
|
||||||
|
if (!Strings.isEmpty(id) && this.state.viewer) {
|
||||||
|
console.log("redirecting to page");
|
||||||
|
this._handleNavigateTo({ id, user, slate, cid });
|
||||||
|
} else {
|
||||||
|
this._handleAction({ type: "NAVIGATE", value: "V1_NAVIGATION_HOME" });
|
||||||
|
}
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -696,8 +705,8 @@ export default class ApplicationPage extends React.Component {
|
|||||||
|
|
||||||
if (jwt) {
|
if (jwt) {
|
||||||
cookies.remove(Credentials.session.key);
|
cookies.remove(Credentials.session.key);
|
||||||
window.location.reload();
|
|
||||||
}
|
}
|
||||||
|
window.location.replace("/_");
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleViewerChange = (e) => {
|
_handleViewerChange = (e) => {
|
||||||
@ -722,7 +731,13 @@ export default class ApplicationPage extends React.Component {
|
|||||||
// + e.g. to display <SceneProfile/> while on the Home tab
|
// + e.g. to display <SceneProfile/> while on the Home tab
|
||||||
// + `scene` should be the decorator of the component you want displayed
|
// + `scene` should be the decorator of the component you want displayed
|
||||||
return this._handleNavigateTo(
|
return this._handleNavigateTo(
|
||||||
{ id: options.value, scene: options.scene, user: options.user, slate: options.slate },
|
{
|
||||||
|
id: options.value,
|
||||||
|
scene: options.scene,
|
||||||
|
user: options.user,
|
||||||
|
slate: options.slate,
|
||||||
|
cid: options.cid,
|
||||||
|
},
|
||||||
options.data,
|
options.data,
|
||||||
options.redirect
|
options.redirect
|
||||||
);
|
);
|
||||||
@ -760,13 +775,17 @@ export default class ApplicationPage extends React.Component {
|
|||||||
return alert(JSON.stringify(options));
|
return alert(JSON.stringify(options));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_handleUpdateData = ({ data }) => {
|
||||||
|
this.setState({ data });
|
||||||
|
};
|
||||||
|
|
||||||
_handleNavigateTo = (next, data = null, redirect = false) => {
|
_handleNavigateTo = (next, data = null, redirect = false) => {
|
||||||
if (next.id) {
|
if (next.id) {
|
||||||
window.history.replaceState(
|
window.history.replaceState(
|
||||||
{ ...next },
|
{ ...next },
|
||||||
"Slate",
|
"Slate",
|
||||||
`?scene=${next.id}${next.user ? `&user=${next.user}` : ""}${
|
`?scene=${next.id}${next.user ? `&user=${next.user}` : ""}${
|
||||||
next.slate ? `&slate=${next.slate}` : ""
|
next.slate ? `&slate=${next.slate}${next.cid ? `&cid=${next.cid}` : ""}` : ""
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -909,6 +928,7 @@ export default class ApplicationPage extends React.Component {
|
|||||||
onUpload: this._handleUploadFiles,
|
onUpload: this._handleUploadFiles,
|
||||||
onBack: this._handleBack,
|
onBack: this._handleBack,
|
||||||
onForward: this._handleForward,
|
onForward: this._handleForward,
|
||||||
|
onUpdateData: this._handleUpdateData,
|
||||||
sceneId: current.target.id,
|
sceneId: current.target.id,
|
||||||
mobile: this.state.mobile,
|
mobile: this.state.mobile,
|
||||||
resources: this.props.resources,
|
resources: this.props.resources,
|
||||||
|
@ -152,7 +152,6 @@ export default class ApplicationHeader extends React.Component {
|
|||||||
//--> argue with haris about how that looks
|
//--> argue with haris about how that looks
|
||||||
|
|
||||||
_handleKeyDown = (e) => {
|
_handleKeyDown = (e) => {
|
||||||
console.log(e.key);
|
|
||||||
let prevValue = this.keysPressed[e.key];
|
let prevValue = this.keysPressed[e.key];
|
||||||
if (prevValue) {
|
if (prevValue) {
|
||||||
return;
|
return;
|
||||||
@ -166,12 +165,10 @@ export default class ApplicationHeader extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handleKeyUp = (e) => {
|
_handleKeyUp = (e) => {
|
||||||
console.log("key up");
|
|
||||||
this.keysPressed = {};
|
this.keysPressed = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleCreateSearch = (e) => {
|
_handleCreateSearch = (e) => {
|
||||||
console.log("create search");
|
|
||||||
dispatchCustomEvent({
|
dispatchCustomEvent({
|
||||||
name: "show-search",
|
name: "show-search",
|
||||||
detail: {},
|
detail: {},
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as Constants from "~/common/constants";
|
import * as Constants from "~/common/constants";
|
||||||
import * as System from "~/components/system";
|
import * as System from "~/components/system";
|
||||||
|
import * as Actions from "~/common/actions";
|
||||||
|
import * as Credentials from "~/common/credentials";
|
||||||
|
|
||||||
import { css } from "@emotion/core";
|
import { css } from "@emotion/core";
|
||||||
import { Logo } from "~/common/logo";
|
import { Logo } from "~/common/logo";
|
||||||
|
import { SignIn } from "~/components/core/SignIn";
|
||||||
|
|
||||||
const STYLES_BACKGROUND = css`
|
const STYLES_BACKGROUND = css`
|
||||||
z-index: ${Constants.zindex.tooltip};
|
z-index: ${Constants.zindex.tooltip};
|
||||||
@ -79,22 +82,13 @@ const STYLES_LINK_ITEM = css`
|
|||||||
transition: 200ms ease all;
|
transition: 200ms ease all;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
|
||||||
:visited {
|
|
||||||
color: ${Constants.system.black};
|
|
||||||
}
|
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
color: ${Constants.system.brand};
|
color: ${Constants.system.brand};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CTATransition = (props) => {
|
export default class CTATransition extends React.Component {
|
||||||
const [open, setOpen] = React.useState(false);
|
render() {
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
setOpen(props.open);
|
|
||||||
}, [props.open]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{open && (
|
{open && (
|
||||||
@ -108,12 +102,12 @@ export const CTATransition = (props) => {
|
|||||||
<System.P style={{ margin: "56px 0", textAlign: "center" }}>
|
<System.P style={{ margin: "56px 0", textAlign: "center" }}>
|
||||||
An open-source file sharing network for research and collaboration
|
An open-source file sharing network for research and collaboration
|
||||||
</System.P>
|
</System.P>
|
||||||
<a href="https://slate.host/_" style={{ textDecoration: `none` }}>
|
<a href={this.props.redirectURL} style={{ textDecoration: `none` }}>
|
||||||
<System.ButtonPrimary full style={{ marginBottom: 16 }}>
|
<System.ButtonPrimary full style={{ marginBottom: 16 }}>
|
||||||
Continue to sign up
|
Continue to sign up
|
||||||
</System.ButtonPrimary>{" "}
|
</System.ButtonPrimary>{" "}
|
||||||
</a>
|
</a>
|
||||||
<a css={STYLES_LINK_ITEM} href="https://slate.host/_">
|
<a css={STYLES_LINK_ITEM} href={this.props.redirectURL}>
|
||||||
Already have an account?
|
Already have an account?
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -122,6 +116,5 @@ export const CTATransition = (props) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
export default CTATransition;
|
|
||||||
|
@ -274,10 +274,14 @@ export default class Profile extends React.Component {
|
|||||||
|
|
||||||
{this.state.visible && (
|
{this.state.visible && (
|
||||||
<div>
|
<div>
|
||||||
<CTATransition open={this.state.visible} />
|
<CTATransition
|
||||||
<a css={STYLES_DISMISS_BOX} onClick={() => this.setState({ visible: false })}>
|
viewer={this.props.viewer}
|
||||||
|
open={this.state.visible}
|
||||||
|
redirectURL={`/_?scene=V1_NAVIGATION_PROFILE&user=${data.username}`}
|
||||||
|
/>
|
||||||
|
<div css={STYLES_DISMISS_BOX} onClick={() => this.setState({ visible: false })}>
|
||||||
<SVG.Dismiss height="24px" />
|
<SVG.Dismiss height="24px" />
|
||||||
</a>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
449
components/core/SignIn.js
Normal file
449
components/core/SignIn.js
Normal file
@ -0,0 +1,449 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import * as Actions from "~/common/actions";
|
||||||
|
import * as System from "~/components/system";
|
||||||
|
import * as Constants from "~/common/constants";
|
||||||
|
import * as Validations from "~/common/validations";
|
||||||
|
import * as Strings from "~/common/strings";
|
||||||
|
|
||||||
|
import { css } from "@emotion/core";
|
||||||
|
import { Logo, Symbol } from "~/common/logo";
|
||||||
|
import { dispatchCustomEvent } from "~/common/custom-events";
|
||||||
|
|
||||||
|
const delay = (time) =>
|
||||||
|
new Promise((resolve) =>
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, time)
|
||||||
|
);
|
||||||
|
|
||||||
|
const STYLES_POPOVER = css`
|
||||||
|
height: 424px;
|
||||||
|
padding: 32px 36px;
|
||||||
|
border-radius: 4px;
|
||||||
|
max-width: 376px;
|
||||||
|
width: 95vw;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: ${Constants.system.white};
|
||||||
|
color: ${Constants.system.black};
|
||||||
|
${"" /* box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.25); */}
|
||||||
|
box-shadow: 0 0 30px 0 rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
@keyframes authentication-popover-fade-in {
|
||||||
|
from {
|
||||||
|
transform: translateY(-8px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateY(0px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
animation: authentication-popover-fade-in 400ms ease;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const STYLES_LINKS = css`
|
||||||
|
margin-top: 24px;
|
||||||
|
max-width: 376px;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 26px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const STYLES_LINK_ITEM = css`
|
||||||
|
display: block;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: ${Constants.font.semiBold};
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 2px;
|
||||||
|
color: ${Constants.system.black};
|
||||||
|
transition: 200ms ease all;
|
||||||
|
word-wrap: break-word;
|
||||||
|
|
||||||
|
:visited {
|
||||||
|
color: ${Constants.system.black};
|
||||||
|
}
|
||||||
|
|
||||||
|
:hover {
|
||||||
|
color: ${Constants.system.brand};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export class SignIn extends React.Component {
|
||||||
|
state = {
|
||||||
|
scene: "WELCOME",
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
loading: false,
|
||||||
|
usernameTaken: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// window.history.replaceState({ id: null }, "Slate", `/_`);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleChange = (e) => {
|
||||||
|
if (e.target.name === "accepted" && e.target.value) {
|
||||||
|
const hash = Strings.generateRandomString();
|
||||||
|
const confirm = window.prompt(`Please type ${hash} to continue.`);
|
||||||
|
|
||||||
|
if (confirm !== hash) {
|
||||||
|
window.alert("Please try again.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ [e.target.name]: e.target.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleUsernameChange = (e) => {
|
||||||
|
const value = Strings.createSlug(e.target.value, "");
|
||||||
|
this.setState({ [e.target.name]: value, usernameTaken: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleSubmit = async () => {
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
await delay(100);
|
||||||
|
|
||||||
|
if (!this.state.accepted && this.state.scene === "CREATE_ACCOUNT") {
|
||||||
|
dispatchCustomEvent({
|
||||||
|
name: "create-alert",
|
||||||
|
detail: {
|
||||||
|
alert: {
|
||||||
|
message: "You must accept the terms of service to create an account",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.setState({ loading: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Validations.username(this.state.username)) {
|
||||||
|
dispatchCustomEvent({
|
||||||
|
name: "create-alert",
|
||||||
|
detail: {
|
||||||
|
alert: {
|
||||||
|
message:
|
||||||
|
this.state.scene === "CREATE_ACCOUNT"
|
||||||
|
? "Usernames must between 1-48 characters and consist of only characters and numbers"
|
||||||
|
: "Invalid username",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.setState({ loading: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Validations.password(this.state.password)) {
|
||||||
|
dispatchCustomEvent({
|
||||||
|
name: "create-alert",
|
||||||
|
detail: {
|
||||||
|
alert: {
|
||||||
|
message:
|
||||||
|
this.state.scene === "CREATE_ACCOUNT"
|
||||||
|
? "Your password must be at least 8 characters"
|
||||||
|
: "Incorrect password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.setState({ loading: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = null;
|
||||||
|
|
||||||
|
if (this.state.scene === "CREATE_ACCOUNT") {
|
||||||
|
response = await this.props.onCreateUser({
|
||||||
|
username: this.state.username.toLowerCase(),
|
||||||
|
password: this.state.password,
|
||||||
|
accepted: this.state.accepted,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
response = await this.props.onAuthenticate({
|
||||||
|
username: this.state.username.toLowerCase(),
|
||||||
|
password: this.state.password,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response) {
|
||||||
|
dispatchCustomEvent({
|
||||||
|
name: "create-alert",
|
||||||
|
detail: {
|
||||||
|
alert: {
|
||||||
|
message: "1We're having trouble connecting right now. Please try again later.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.setState({ loading: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
dispatchCustomEvent({
|
||||||
|
name: "create-alert",
|
||||||
|
detail: { alert: { decorator: response.decorator } },
|
||||||
|
});
|
||||||
|
this.setState({ loading: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({ scene: "whatever" });
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleCheckUsername = async () => {
|
||||||
|
if (!this.state.username || !this.state.username.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Validations.username(this.state.username)) {
|
||||||
|
dispatchCustomEvent({
|
||||||
|
name: "create-alert",
|
||||||
|
detail: {
|
||||||
|
alert: {
|
||||||
|
message:
|
||||||
|
"Usernames must between 1-48 characters and consist of only characters and numbers",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await Actions.checkUsername({
|
||||||
|
username: this.state.username.toLowerCase(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response) {
|
||||||
|
dispatchCustomEvent({
|
||||||
|
name: "create-alert",
|
||||||
|
detail: {
|
||||||
|
alert: {
|
||||||
|
message: "2We're having trouble connecting right now. Please try again later.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
dispatchCustomEvent({
|
||||||
|
name: "create-alert",
|
||||||
|
detail: {
|
||||||
|
alert: {
|
||||||
|
decorator: response.decorator,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.data) {
|
||||||
|
//NOTE(martina): username taken
|
||||||
|
this.setState({ usernameTaken: true });
|
||||||
|
dispatchCustomEvent({
|
||||||
|
name: "create-alert",
|
||||||
|
detail: {
|
||||||
|
alert: {
|
||||||
|
message: "That username is taken",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE(martina): username not taken
|
||||||
|
return this.setState({
|
||||||
|
usernameTaken: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.scene === "WELCOME") {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div css={STYLES_POPOVER} key={this.state.scene}>
|
||||||
|
<Logo height="36px" style={{ display: "block", margin: "56px auto 0px auto" }} />
|
||||||
|
|
||||||
|
<System.P style={{ margin: "56px 0", textAlign: "center" }}>
|
||||||
|
{this.props.external
|
||||||
|
? "Sign up or sign in to continue"
|
||||||
|
: "An open-source file sharing network for research and collaboration"}
|
||||||
|
</System.P>
|
||||||
|
|
||||||
|
<System.ButtonPrimary
|
||||||
|
full
|
||||||
|
style={{ marginTop: 24 }}
|
||||||
|
onClick={() => this.setState({ scene: "CREATE_ACCOUNT" })}
|
||||||
|
loading={this.state.loading}
|
||||||
|
>
|
||||||
|
Sign up
|
||||||
|
</System.ButtonPrimary>
|
||||||
|
|
||||||
|
<System.ButtonSecondary
|
||||||
|
full
|
||||||
|
style={{ marginTop: 16 }}
|
||||||
|
onClick={() => this.setState({ scene: "SIGN_IN" })}
|
||||||
|
loading={this.state.loading}
|
||||||
|
>
|
||||||
|
Log in
|
||||||
|
</System.ButtonSecondary>
|
||||||
|
</div>
|
||||||
|
<div css={STYLES_LINKS}>
|
||||||
|
<a css={STYLES_LINK_ITEM} href="/terms" target="_blank">
|
||||||
|
⭢ Terms of service
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a css={STYLES_LINK_ITEM} href="/guidelines" target="_blank">
|
||||||
|
⭢ Community guidelines
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.scene === "CREATE_ACCOUNT") {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div css={STYLES_POPOVER} key={this.state.scene} style={{ minHeight: 496 }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
paddingTop: 56,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Symbol height="36px" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<System.P
|
||||||
|
style={{
|
||||||
|
marginTop: 56,
|
||||||
|
textAlign: "center",
|
||||||
|
fontFamily: Constants.font.medium,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Create your account
|
||||||
|
</System.P>
|
||||||
|
|
||||||
|
<System.Input
|
||||||
|
autoFocus
|
||||||
|
containerStyle={{ marginTop: 32 }}
|
||||||
|
placeholder="Username"
|
||||||
|
name="username"
|
||||||
|
type="text"
|
||||||
|
value={this.state.username}
|
||||||
|
onChange={this._handleUsernameChange}
|
||||||
|
onBlur={this._handleCheckUsername}
|
||||||
|
onSubmit={this._handleSubmit}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<System.Input
|
||||||
|
containerStyle={{ marginTop: 16 }}
|
||||||
|
placeholder="Password"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
value={this.state.password}
|
||||||
|
onChange={this._handleChange}
|
||||||
|
onSubmit={this._handleSubmit}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<System.CheckBox
|
||||||
|
style={{ marginTop: 24 }}
|
||||||
|
name="accepted"
|
||||||
|
value={this.state.accepted}
|
||||||
|
onChange={this._handleChange}
|
||||||
|
>
|
||||||
|
To create an account you must accept the <a href="/terms">terms of service</a>.
|
||||||
|
</System.CheckBox>
|
||||||
|
|
||||||
|
<System.ButtonPrimary
|
||||||
|
full
|
||||||
|
style={{ marginTop: 24 }}
|
||||||
|
onClick={!this.state.loading ? this._handleSubmit : () => {}}
|
||||||
|
loading={this.state.loading}
|
||||||
|
>
|
||||||
|
Sign up
|
||||||
|
</System.ButtonPrimary>
|
||||||
|
</div>
|
||||||
|
<div css={STYLES_LINKS}>
|
||||||
|
<div
|
||||||
|
css={STYLES_LINK_ITEM}
|
||||||
|
onClick={() => {
|
||||||
|
this.setState({ scene: "SIGN_IN", loading: false });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
⭢ Already have an account?
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div css={STYLES_POPOVER} key={this.state.scene}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
paddingTop: 56,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Symbol height="36px" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<System.P
|
||||||
|
style={{
|
||||||
|
marginTop: 56,
|
||||||
|
textAlign: "center",
|
||||||
|
fontFamily: Constants.font.medium,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Welcome back
|
||||||
|
</System.P>
|
||||||
|
|
||||||
|
<System.Input
|
||||||
|
autoFocus
|
||||||
|
containerStyle={{ marginTop: 32 }}
|
||||||
|
placeholder="Username"
|
||||||
|
name="username"
|
||||||
|
type="text"
|
||||||
|
value={this.state.username}
|
||||||
|
onChange={this._handleUsernameChange}
|
||||||
|
onSubmit={this._handleSubmit}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<System.Input
|
||||||
|
containerStyle={{ marginTop: 16 }}
|
||||||
|
placeholder="Password"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
value={this.state.password}
|
||||||
|
onChange={this._handleChange}
|
||||||
|
onSubmit={this._handleSubmit}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<System.ButtonPrimary
|
||||||
|
full
|
||||||
|
style={{ marginTop: 24 }}
|
||||||
|
onClick={!this.state.loading ? this._handleSubmit : () => {}}
|
||||||
|
loading={this.state.loading}
|
||||||
|
>
|
||||||
|
Log in
|
||||||
|
</System.ButtonPrimary>
|
||||||
|
</div>
|
||||||
|
<div css={STYLES_LINKS}>
|
||||||
|
<div
|
||||||
|
css={STYLES_LINK_ITEM}
|
||||||
|
onClick={() => {
|
||||||
|
this.setState({ scene: "CREATE_ACCOUNT", loading: false });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
⭢ Not registered? Sign up instead
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ import * as Window from "~/common/window";
|
|||||||
import * as Validations from "~/common/validations";
|
import * as Validations from "~/common/validations";
|
||||||
|
|
||||||
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
|
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
|
||||||
|
import CTATransition from "~/components/core/CTATransition";
|
||||||
|
|
||||||
import { CheckBox } from "~/components/system/components/CheckBox";
|
import { CheckBox } from "~/components/system/components/CheckBox";
|
||||||
import { css } from "@emotion/core";
|
import { css } from "@emotion/core";
|
||||||
@ -282,6 +283,19 @@ const STYLES_ICON_ROW = css`
|
|||||||
left: calc(50% - 60px);
|
left: calc(50% - 60px);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const STYLES_DISMISS_BOX = css`
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
right: 16px;
|
||||||
|
color: ${Constants.system.darkGray};
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: ${Constants.zindex.tooltip};
|
||||||
|
|
||||||
|
:hover {
|
||||||
|
color: ${Constants.system.white};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export class SlateLayout extends React.Component {
|
export class SlateLayout extends React.Component {
|
||||||
_ref;
|
_ref;
|
||||||
_input;
|
_input;
|
||||||
@ -306,6 +320,7 @@ export class SlateLayout extends React.Component {
|
|||||||
copyValue: "",
|
copyValue: "",
|
||||||
tooltip: null,
|
tooltip: null,
|
||||||
keyboardTooltip: false,
|
keyboardTooltip: false,
|
||||||
|
signInModal: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
//LEFT OFF HERE:
|
//LEFT OFF HERE:
|
||||||
@ -971,13 +986,6 @@ export class SlateLayout extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleLoginModal = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
//TODO(martina): add a modal popup that says "login or sign up to use this feature", and automatically redirect to in-client view if already logged in
|
|
||||||
window.location.pathname = "/_";
|
|
||||||
};
|
|
||||||
|
|
||||||
_handleSetPreview = (e, i) => {
|
_handleSetPreview = (e, i) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -1094,6 +1102,12 @@ export class SlateLayout extends React.Component {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_handleLoginModal = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
this.setState({ signInModal: true });
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let numChecked = Object.keys(this.state.checked).length;
|
let numChecked = Object.keys(this.state.checked).length;
|
||||||
let unit = this.state.unit;
|
let unit = this.state.unit;
|
||||||
@ -1800,6 +1814,18 @@ export class SlateLayout extends React.Component {
|
|||||||
value={this.state.copyValue}
|
value={this.state.copyValue}
|
||||||
css={STYLES_COPY_INPUT}
|
css={STYLES_COPY_INPUT}
|
||||||
/>
|
/>
|
||||||
|
{this.props.external && this.state.signInModal && (
|
||||||
|
<div>
|
||||||
|
<CTATransition
|
||||||
|
viewer={this.props.viewer}
|
||||||
|
open={this.state.signInModal}
|
||||||
|
redirectURL={`/_?scene=V1_NAVIGATION_SLATE&user=${this.props.creator.username}&slate=${this.props.slate.slatename}`}
|
||||||
|
/>
|
||||||
|
<div css={STYLES_DISMISS_BOX} onClick={() => this.setState({ signInModal: false })}>
|
||||||
|
<SVG.Dismiss height="24px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -300,6 +300,17 @@ export const hydrate = async (id) => {
|
|||||||
websocketSend("UPDATE", data);
|
websocketSend("UPDATE", data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const checkId = async ({ id }) => {
|
||||||
|
const user = await Data.getUserById({
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user || user.error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// TODO(jim): Work on better serialization when adoption starts occuring.
|
// TODO(jim): Work on better serialization when adoption starts occuring.
|
||||||
export const getById = async ({ id }) => {
|
export const getById = async ({ id }) => {
|
||||||
const user = await Data.getUserById({
|
const user = await Data.getUserById({
|
||||||
|
@ -10,12 +10,12 @@ import { css } from "@emotion/core";
|
|||||||
import { ProcessedText } from "~/components/system/components/Typography";
|
import { ProcessedText } from "~/components/system/components/Typography";
|
||||||
import { Alert } from "~/components/core/Alert";
|
import { Alert } from "~/components/core/Alert";
|
||||||
import { ViewAllButton } from "~/components/core/ViewAll";
|
import { ViewAllButton } from "~/components/core/ViewAll";
|
||||||
|
import { SlateLayout } from "~/components/core/SlateLayout";
|
||||||
|
import { SlateLayoutMobile } from "~/components/core/SlateLayoutMobile";
|
||||||
|
|
||||||
import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper";
|
import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper";
|
||||||
import WebsitePrototypeHeader from "~/components/core/WebsitePrototypeHeader";
|
import WebsitePrototypeHeader from "~/components/core/WebsitePrototypeHeader";
|
||||||
import WebsitePrototypeFooter from "~/components/core/WebsitePrototypeFooter";
|
import WebsitePrototypeFooter from "~/components/core/WebsitePrototypeFooter";
|
||||||
import { SlateLayout } from "~/components/core/SlateLayout";
|
|
||||||
import { SlateLayoutMobile } from "~/components/core/SlateLayoutMobile";
|
|
||||||
import SlateMediaObject from "~/components/core/SlateMediaObject";
|
import SlateMediaObject from "~/components/core/SlateMediaObject";
|
||||||
import CTATransition from "~/components/core/CTATransition";
|
import CTATransition from "~/components/core/CTATransition";
|
||||||
|
|
||||||
@ -320,19 +320,19 @@ export default class SlatePage extends React.Component {
|
|||||||
<div css={STYLES_ROOT}>
|
<div css={STYLES_ROOT}>
|
||||||
<WebsitePrototypeHeader />
|
<WebsitePrototypeHeader />
|
||||||
<div css={STYLES_SLATE_INTRO}>
|
<div css={STYLES_SLATE_INTRO}>
|
||||||
<a css={STYLES_CREATOR} href={headerURL}>
|
<a css={STYLES_CREATOR} href={`/${this.props.creator.username}`}>
|
||||||
{slateCreator}
|
{slateCreator}
|
||||||
</a>
|
</a>
|
||||||
<div css={STYLES_DESCTIPTION}>
|
<div css={STYLES_DESCTIPTION}>
|
||||||
<div css={STYLES_FLEX}>
|
<div css={STYLES_FLEX}>
|
||||||
<div css={STYLES_TITLE}>{slateTitle} </div>
|
<div css={STYLES_TITLE}>{slateTitle} </div>
|
||||||
<div css={STYLES_BUTTONS}>
|
<div css={STYLES_BUTTONS}>
|
||||||
<a css={STYLES_BUTTON} onClick={() => this.setState({ visible: true })}>
|
<div css={STYLES_BUTTON} onClick={() => this.setState({ visible: true })}>
|
||||||
Follow
|
Follow
|
||||||
</a>
|
</div>
|
||||||
<a css={STYLES_BUTTON} onClick={() => this.setState({ visible: true })}>
|
<div css={STYLES_BUTTON} onClick={() => this.setState({ visible: true })}>
|
||||||
Download
|
Download
|
||||||
</a>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ViewAllButton fullText={this.props.slate.data.body} maxCharacter={208}>
|
<ViewAllButton fullText={this.props.slate.data.body} maxCharacter={208}>
|
||||||
@ -375,6 +375,8 @@ export default class SlatePage extends React.Component {
|
|||||||
items={objects}
|
items={objects}
|
||||||
onSelect={this._handleSelect}
|
onSelect={this._handleSelect}
|
||||||
defaultLayout={layouts && layouts.ver === "2.0" ? layouts.defaultLayout : true}
|
defaultLayout={layouts && layouts.ver === "2.0" ? layouts.defaultLayout : true}
|
||||||
|
creator={this.props.creator}
|
||||||
|
slate={this.props.slate}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -383,10 +385,14 @@ export default class SlatePage extends React.Component {
|
|||||||
<System.GlobalModal />
|
<System.GlobalModal />
|
||||||
{this.state.visible && (
|
{this.state.visible && (
|
||||||
<div>
|
<div>
|
||||||
<CTATransition open={this.state.visible} />
|
<CTATransition
|
||||||
<a css={STYLES_DISMISS_BOX} onClick={() => this.setState({ visible: false })}>
|
viewer={this.props.viewer}
|
||||||
|
open={this.state.visible}
|
||||||
|
redirectURL={`/_?scene=V1_NAVIGATION_SLATE&user=${this.props.creator.username}&slate=${this.props.slate.slatename}`}
|
||||||
|
/>
|
||||||
|
<div css={STYLES_DISMISS_BOX} onClick={() => this.setState({ visible: false })}>
|
||||||
<SVG.Dismiss height="24px" />
|
<SVG.Dismiss height="24px" />
|
||||||
</a>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<WebsitePrototypeFooter />
|
<WebsitePrototypeFooter />
|
||||||
|
@ -56,5 +56,9 @@ export default async (req, res) => {
|
|||||||
|
|
||||||
const token = JWT.sign({ id: user.id, username: user.username }, Environment.JWT_SECRET);
|
const token = JWT.sign({ id: user.id, username: user.username }, Environment.JWT_SECRET);
|
||||||
|
|
||||||
return res.status(200).send({ decorator: "SERVER_SIGN_IN", success: true, token });
|
res.status(200).send({ decorator: "SERVER_SIGN_IN", success: true, token });
|
||||||
|
if (req.body.data.redirectURL) {
|
||||||
|
console.log(req.body.data.redirectURL);
|
||||||
|
res.redirect(req.body.data.redirectURL);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -26,19 +26,15 @@ export default class ScenePublicProfile extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
componentDidUpdate = async (prevProps) => {
|
componentDidUpdate = async (prevProps) => {
|
||||||
if (!this.props.data) {
|
if (
|
||||||
return null;
|
this.props.data &&
|
||||||
}
|
prevProps.data &&
|
||||||
|
this.props.data.id &&
|
||||||
if (!prevProps.data) {
|
prevProps.data.id &&
|
||||||
return null;
|
this.props.data.id !== prevProps.data.id
|
||||||
}
|
) {
|
||||||
|
|
||||||
if (!prevProps.data.id || this.props.data.id === prevProps.data.id) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.fetchProfile();
|
await this.fetchProfile();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchProfile = async () => {
|
fetchProfile = async () => {
|
||||||
@ -55,12 +51,12 @@ export default class ScenePublicProfile extends React.Component {
|
|||||||
} else {
|
} else {
|
||||||
query = { id: this.props.viewer.id };
|
query = { id: this.props.viewer.id };
|
||||||
}
|
}
|
||||||
let profile;
|
let response;
|
||||||
if (query) {
|
if (query) {
|
||||||
profile = await Actions.getSerializedProfile(query);
|
response = await Actions.getSerializedProfile(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!profile || profile.error) {
|
if (!response || response.error) {
|
||||||
dispatchCustomEvent({
|
dispatchCustomEvent({
|
||||||
name: "create-alert",
|
name: "create-alert",
|
||||||
detail: { alert: { message: "We're having trouble fetching that user right now." } },
|
detail: { alert: { message: "We're having trouble fetching that user right now." } },
|
||||||
@ -69,7 +65,8 @@ export default class ScenePublicProfile extends React.Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ profile: profile.data });
|
this.props.onUpdateData({ data: response.data });
|
||||||
|
this.setState({ profile: response.data });
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as Actions from "~/common/actions";
|
import * as Actions from "~/common/actions";
|
||||||
import * as Window from "~/common/window";
|
import * as Window from "~/common/window";
|
||||||
|
import * as Strings from "~/common/strings";
|
||||||
|
|
||||||
import { LoaderSpinner } from "~/components/system/components/Loaders";
|
import { LoaderSpinner } from "~/components/system/components/Loaders";
|
||||||
import { css } from "@emotion/core";
|
import { css } from "@emotion/core";
|
||||||
@ -26,24 +27,22 @@ export default class ScenePublicSlate extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
componentDidUpdate = async (prevProps) => {
|
componentDidUpdate = async (prevProps) => {
|
||||||
if (!this.props.data) {
|
if (
|
||||||
return null;
|
this.props.data &&
|
||||||
}
|
prevProps.data &&
|
||||||
|
this.props.data.id &&
|
||||||
if (!prevProps.data) {
|
prevProps.data.id &&
|
||||||
return null;
|
this.props.data.id !== prevProps.data.id
|
||||||
}
|
) {
|
||||||
|
|
||||||
if (this.props.data.id === prevProps.data.id) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.fetchSlate();
|
await this.fetchSlate();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchSlate = async () => {
|
fetchSlate = async () => {
|
||||||
|
console.log(this.props.data);
|
||||||
const username = Window.getQueryParameterByName("user");
|
const username = Window.getQueryParameterByName("user");
|
||||||
const slatename = Window.getQueryParameterByName("slate");
|
const slatename = Window.getQueryParameterByName("slate");
|
||||||
|
const cid = Window.getQueryParameterByName("cid");
|
||||||
if (
|
if (
|
||||||
!this.props.data &&
|
!this.props.data &&
|
||||||
!username &&
|
!username &&
|
||||||
@ -92,20 +91,40 @@ export default class ScenePublicSlate extends React.Component {
|
|||||||
} else if (this.props.data && this.props.data.id) {
|
} else if (this.props.data && this.props.data.id) {
|
||||||
query = { id: this.props.data.id };
|
query = { id: this.props.data.id };
|
||||||
}
|
}
|
||||||
let slate;
|
let response;
|
||||||
if (query) {
|
if (query) {
|
||||||
slate = await Actions.getSerializedSlate(query);
|
response = await Actions.getSerializedSlate(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!slate || slate.error) {
|
if (!response || response.error) {
|
||||||
dispatchCustomEvent({
|
dispatchCustomEvent({
|
||||||
name: "create-alert",
|
name: "create-alert",
|
||||||
detail: { alert: { message: "We're having trouble fetching that slate right now." } },
|
detail: { alert: { message: "We're having trouble fetching that slate right now." } },
|
||||||
});
|
});
|
||||||
this.props.onBack();
|
this.props.onBack();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ slate: slate.data });
|
this.props.onUpdateData({ data: response.data });
|
||||||
|
this.setState({ slate: response.data });
|
||||||
|
|
||||||
|
if (!Strings.isEmpty(cid)) {
|
||||||
|
let index = -1;
|
||||||
|
for (let i = 0; i < response.data.data.objects.length; i++) {
|
||||||
|
let obj = response.data.data.objects[i];
|
||||||
|
if ((obj.cid && obj.cid === cid) || (obj.url && obj.url.includes(cid))) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index !== -1) {
|
||||||
|
dispatchCustomEvent({
|
||||||
|
name: "slate-global-open-carousel",
|
||||||
|
detail: { index },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -6,7 +6,7 @@ import * as Validations from "~/common/validations";
|
|||||||
import * as Strings from "~/common/strings";
|
import * as Strings from "~/common/strings";
|
||||||
|
|
||||||
import { css } from "@emotion/core";
|
import { css } from "@emotion/core";
|
||||||
import { Logo, Symbol } from "~/common/logo";
|
import { SignIn } from "~/components/core/SignIn";
|
||||||
import { dispatchCustomEvent } from "~/common/custom-events";
|
import { dispatchCustomEvent } from "~/common/custom-events";
|
||||||
|
|
||||||
import WebsitePrototypeHeader from "~/components/core/WebsitePrototypeHeader";
|
import WebsitePrototypeHeader from "~/components/core/WebsitePrototypeHeader";
|
||||||
@ -47,71 +47,6 @@ const STYLES_MIDDLE = css`
|
|||||||
padding: 24px;
|
padding: 24px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_POPOVER = css`
|
|
||||||
height: 424px;
|
|
||||||
padding: 32px 36px;
|
|
||||||
border-radius: 4px;
|
|
||||||
max-width: 376px;
|
|
||||||
width: 95vw;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: ${Constants.system.white};
|
|
||||||
color: ${Constants.system.black};
|
|
||||||
${"" /* box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.25); */}
|
|
||||||
box-shadow: 0 0 30px 0 rgba(0, 0, 0, 0.05);
|
|
||||||
|
|
||||||
@keyframes authentication-popover-fade-in {
|
|
||||||
from {
|
|
||||||
transform: translateY(-8px);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
transform: translateY(0px);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
animation: authentication-popover-fade-in 400ms ease;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STYLES_LINKS = css`
|
|
||||||
margin-top: 24px;
|
|
||||||
max-width: 376px;
|
|
||||||
width: 100%;
|
|
||||||
padding-left: 26px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STYLES_LINK_ITEM = css`
|
|
||||||
display: block;
|
|
||||||
text-decoration: none;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 14px;
|
|
||||||
font-family: ${Constants.font.semiBold};
|
|
||||||
user-select: none;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-top: 2px;
|
|
||||||
color: ${Constants.system.black};
|
|
||||||
transition: 200ms ease all;
|
|
||||||
word-wrap: break-word;
|
|
||||||
|
|
||||||
:visited {
|
|
||||||
color: ${Constants.system.black};
|
|
||||||
}
|
|
||||||
|
|
||||||
:hover {
|
|
||||||
color: ${Constants.system.brand};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STYLES_CODE_PREVIEW = css`
|
|
||||||
color: ${Constants.system.black};
|
|
||||||
font-family: ${Constants.font.code};
|
|
||||||
font-size: 12px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default class SceneSignIn extends React.Component {
|
export default class SceneSignIn extends React.Component {
|
||||||
state = {
|
state = {
|
||||||
scene: "WELCOME",
|
scene: "WELCOME",
|
||||||
@ -121,9 +56,9 @@ export default class SceneSignIn extends React.Component {
|
|||||||
usernameTaken: false,
|
usernameTaken: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
// componentDidMount() {
|
||||||
window.history.replaceState({ id: null }, "Slate", `/_`);
|
// window.history.replaceState({ id: null }, "Slate", `/_`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
_handleChange = (e) => {
|
_handleChange = (e) => {
|
||||||
if (e.target.name === "accepted" && e.target.value) {
|
if (e.target.name === "accepted" && e.target.value) {
|
||||||
@ -297,205 +232,13 @@ export default class SceneSignIn extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_getPopoverComponent = () => {
|
|
||||||
if (this.state.scene === "WELCOME") {
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<div css={STYLES_POPOVER} key={this.state.scene}>
|
|
||||||
<Logo height="36px" style={{ display: "block", margin: "56px auto 0px auto" }} />
|
|
||||||
|
|
||||||
<System.P style={{ margin: "56px 0", textAlign: "center" }}>
|
|
||||||
An open-source file sharing network for research and collaboration
|
|
||||||
</System.P>
|
|
||||||
|
|
||||||
<System.ButtonPrimary
|
|
||||||
full
|
|
||||||
style={{ marginTop: 24 }}
|
|
||||||
onClick={() => this.setState({ scene: "CREATE_ACCOUNT" })}
|
|
||||||
loading={this.state.loading}
|
|
||||||
>
|
|
||||||
Sign up
|
|
||||||
</System.ButtonPrimary>
|
|
||||||
|
|
||||||
<System.ButtonSecondary
|
|
||||||
full
|
|
||||||
style={{ marginTop: 16 }}
|
|
||||||
onClick={() => this.setState({ scene: "SIGN_IN" })}
|
|
||||||
loading={this.state.loading}
|
|
||||||
>
|
|
||||||
Sign in
|
|
||||||
</System.ButtonSecondary>
|
|
||||||
</div>
|
|
||||||
<div css={STYLES_LINKS}>
|
|
||||||
<a css={STYLES_LINK_ITEM} href="/terms" target="_blank">
|
|
||||||
⭢ Terms of service
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a css={STYLES_LINK_ITEM} href="/guidelines" target="_blank">
|
|
||||||
⭢ Community guidelines
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.scene === "CREATE_ACCOUNT") {
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<div css={STYLES_POPOVER} key={this.state.scene} style={{ minHeight: 496 }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
paddingTop: 56,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Symbol height="36px" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<System.P
|
|
||||||
style={{
|
|
||||||
marginTop: 56,
|
|
||||||
textAlign: "center",
|
|
||||||
fontFamily: Constants.font.medium,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Create your account
|
|
||||||
</System.P>
|
|
||||||
|
|
||||||
<System.Input
|
|
||||||
autoFocus
|
|
||||||
containerStyle={{ marginTop: 32 }}
|
|
||||||
placeholder="Username"
|
|
||||||
name="username"
|
|
||||||
type="text"
|
|
||||||
value={this.state.username}
|
|
||||||
onChange={this._handleUsernameChange}
|
|
||||||
onBlur={this._handleCheckUsername}
|
|
||||||
onSubmit={this._handleSubmit}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<System.Input
|
|
||||||
containerStyle={{ marginTop: 16 }}
|
|
||||||
placeholder="Password"
|
|
||||||
name="password"
|
|
||||||
type="password"
|
|
||||||
value={this.state.password}
|
|
||||||
onChange={this._handleChange}
|
|
||||||
onSubmit={this._handleSubmit}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<System.CheckBox
|
|
||||||
style={{ marginTop: 24 }}
|
|
||||||
name="accepted"
|
|
||||||
value={this.state.accepted}
|
|
||||||
onChange={this._handleChange}
|
|
||||||
>
|
|
||||||
To create an account you must accept the <a href="/terms">terms of service</a>.
|
|
||||||
</System.CheckBox>
|
|
||||||
|
|
||||||
<System.ButtonPrimary
|
|
||||||
full
|
|
||||||
style={{ marginTop: 24 }}
|
|
||||||
onClick={!this.state.loading ? this._handleSubmit : () => {}}
|
|
||||||
loading={this.state.loading}
|
|
||||||
>
|
|
||||||
Sign up
|
|
||||||
</System.ButtonPrimary>
|
|
||||||
</div>
|
|
||||||
<div css={STYLES_LINKS}>
|
|
||||||
<div
|
|
||||||
css={STYLES_LINK_ITEM}
|
|
||||||
onClick={() => {
|
|
||||||
this.setState({ scene: "SIGN_IN", loading: false });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
⭢ Already have an account?
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<div css={STYLES_POPOVER} key={this.state.scene}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
paddingTop: 56,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Symbol height="36px" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<System.P
|
|
||||||
style={{
|
|
||||||
marginTop: 56,
|
|
||||||
textAlign: "center",
|
|
||||||
fontFamily: Constants.font.medium,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Welcome back
|
|
||||||
</System.P>
|
|
||||||
|
|
||||||
<System.Input
|
|
||||||
autoFocus
|
|
||||||
containerStyle={{ marginTop: 32 }}
|
|
||||||
placeholder="Username"
|
|
||||||
name="username"
|
|
||||||
type="text"
|
|
||||||
value={this.state.username}
|
|
||||||
onChange={this._handleUsernameChange}
|
|
||||||
onSubmit={this._handleSubmit}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<System.Input
|
|
||||||
containerStyle={{ marginTop: 16 }}
|
|
||||||
placeholder="Password"
|
|
||||||
name="password"
|
|
||||||
type="password"
|
|
||||||
value={this.state.password}
|
|
||||||
onChange={this._handleChange}
|
|
||||||
onSubmit={this._handleSubmit}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<System.ButtonPrimary
|
|
||||||
full
|
|
||||||
style={{ marginTop: 24 }}
|
|
||||||
onClick={!this.state.loading ? this._handleSubmit : () => {}}
|
|
||||||
loading={this.state.loading}
|
|
||||||
>
|
|
||||||
Sign in
|
|
||||||
</System.ButtonPrimary>
|
|
||||||
</div>
|
|
||||||
<div css={STYLES_LINKS}>
|
|
||||||
<div
|
|
||||||
css={STYLES_LINK_ITEM}
|
|
||||||
onClick={() => {
|
|
||||||
this.setState({ scene: "CREATE_ACCOUNT", loading: false });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
⭢ Not registered? Sign up instead
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const popover = this._getPopoverComponent();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div css={STYLES_ROOT}>
|
||||||
css={STYLES_ROOT}
|
|
||||||
// style={{
|
|
||||||
// backgroundImage: `url(${"https://slate.textile.io/ipfs/bafybeigrydo6q24ra4hnqpv6dpoosuar2rwbx6fslug2e2xdlcshayis2q"})`,
|
|
||||||
// }}
|
|
||||||
>
|
|
||||||
<WebsitePrototypeHeader style={{ background: `none` }} />
|
<WebsitePrototypeHeader style={{ background: `none` }} />
|
||||||
<div css={STYLES_MIDDLE}>{popover}</div>
|
<div css={STYLES_MIDDLE}>
|
||||||
|
<SignIn {...this.props} />
|
||||||
|
</div>
|
||||||
<WebsitePrototypeFooter />
|
<WebsitePrototypeFooter />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
39
server.js
39
server.js
@ -199,7 +199,15 @@ app.prepare().then(async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const id = Utilities.getIdFromCookie(req);
|
const id = Utilities.getIdFromCookie(req);
|
||||||
|
const loggedIn = ViewerManager.checkId({ id });
|
||||||
|
if (loggedIn) {
|
||||||
|
return res.redirect(
|
||||||
|
`/_${Strings.createQueryParams({
|
||||||
|
scene: "V1_NAVIGATION_PROFILE",
|
||||||
|
user: req.params.username,
|
||||||
|
})}`
|
||||||
|
);
|
||||||
|
}
|
||||||
let viewer = null;
|
let viewer = null;
|
||||||
if (id) {
|
if (id) {
|
||||||
viewer = await ViewerManager.getById({
|
viewer = await ViewerManager.getById({
|
||||||
@ -243,6 +251,18 @@ app.prepare().then(async () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const id = Utilities.getIdFromCookie(req);
|
||||||
|
const loggedIn = ViewerManager.checkId({ id });
|
||||||
|
if (loggedIn) {
|
||||||
|
return res.redirect(
|
||||||
|
`/_${Strings.createQueryParams({
|
||||||
|
scene: "V1_NAVIGATION_SLATE",
|
||||||
|
user: req.params.username,
|
||||||
|
slate: req.params.slatename,
|
||||||
|
})}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const slate = await Data.getSlateByName({
|
const slate = await Data.getSlateByName({
|
||||||
slatename: req.params.slatename,
|
slatename: req.params.slatename,
|
||||||
username: req.params.username,
|
username: req.params.username,
|
||||||
@ -274,8 +294,6 @@ app.prepare().then(async () => {
|
|||||||
return res.redirect("/403");
|
return res.redirect("/403");
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = Utilities.getIdFromCookie(req);
|
|
||||||
|
|
||||||
let viewer = null;
|
let viewer = null;
|
||||||
if (id) {
|
if (id) {
|
||||||
viewer = await ViewerManager.getById({
|
viewer = await ViewerManager.getById({
|
||||||
@ -298,6 +316,19 @@ app.prepare().then(async () => {
|
|||||||
return handler(req, res, req.url);
|
return handler(req, res, req.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const id = Utilities.getIdFromCookie(req);
|
||||||
|
const loggedIn = ViewerManager.checkId({ id });
|
||||||
|
if (loggedIn) {
|
||||||
|
return res.redirect(
|
||||||
|
`/_${Strings.createQueryParams({
|
||||||
|
scene: "V1_NAVIGATION_SLATE",
|
||||||
|
user: req.params.username,
|
||||||
|
slate: req.params.slatename,
|
||||||
|
cid: req.params.cid,
|
||||||
|
})}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const slate = await Data.getSlateByName({
|
const slate = await Data.getSlateByName({
|
||||||
slatename: req.params.slatename,
|
slatename: req.params.slatename,
|
||||||
username: req.params.username,
|
username: req.params.username,
|
||||||
@ -329,8 +360,6 @@ app.prepare().then(async () => {
|
|||||||
return res.redirect("/403");
|
return res.redirect("/403");
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = Utilities.getIdFromCookie(req);
|
|
||||||
|
|
||||||
let viewer = null;
|
let viewer = null;
|
||||||
if (id) {
|
if (id) {
|
||||||
viewer = await ViewerManager.getById({
|
viewer = await ViewerManager.getById({
|
||||||
|
Loading…
Reference in New Issue
Block a user