mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-24 17:44:50 +03:00
activity feed front end basics
This commit is contained in:
parent
b804027720
commit
73a04b9131
@ -293,3 +293,9 @@ export const createSupportMessage = async (data) => {
|
||||
body: JSON.stringify({ data }),
|
||||
});
|
||||
};
|
||||
|
||||
export const getActivity = async () => {
|
||||
return await returnJSON(`/api/activity/get`, {
|
||||
...DEFAULT_OPTIONS,
|
||||
});
|
||||
};
|
||||
|
@ -14,9 +14,7 @@ export const deal = ({ userId, data }) => {
|
||||
|
||||
const userProfileURL = `https://slate.host/${data.context.username}`;
|
||||
const userURL = `<${userProfileURL}|${data.context.username}>`;
|
||||
const message = `*${userURL}* made a one-off storage deal with bucket "${
|
||||
data.context.bucketName
|
||||
}".`;
|
||||
const message = `*${userURL}* made a one-off storage deal with bucket "${data.context.bucketName}".`;
|
||||
|
||||
Social.sendSlackMessage(message);
|
||||
} catch (e) {
|
||||
@ -57,7 +55,7 @@ const createSlateActivityForEachSubscriber = async ({ userId, data }) => {
|
||||
Data.createActivity({
|
||||
userId: s.owner_user_id,
|
||||
data: {
|
||||
type: "ANOTHER_USER_CREATED_SLATE",
|
||||
type: "OTHER_USER_CREATE_SLATE",
|
||||
actorUserId: data.actorUserId,
|
||||
context: data.context,
|
||||
},
|
||||
@ -83,9 +81,7 @@ export const createSlate = ({ userId, data }) => {
|
||||
|
||||
const userProfileURL = `https://slate.host/${data.context.username}`;
|
||||
const userURL = `<${userProfileURL}|${data.context.username}>`;
|
||||
const message = `*${userURL}* created a slate: https://slate.host/${data.context.username}/${
|
||||
data.context.slatename
|
||||
}`;
|
||||
const message = `*${userURL}* created a slate: https://slate.host/${data.context.username}/${data.context.slatename}`;
|
||||
|
||||
Social.sendSlackMessage(message);
|
||||
} catch (e) {
|
||||
@ -105,7 +101,7 @@ const createSlateObjectActivityForEachSubscriber = async ({ slateId, data }) =>
|
||||
Data.createActivity({
|
||||
userId: s.owner_user_id,
|
||||
data: {
|
||||
type: "ANOTHER_USER_CREATE_SLATE_OBJECT",
|
||||
type: "OTHER_USER_CREATE_SLATE_OBJECT",
|
||||
actorUserId: data.actorUserId,
|
||||
context: data.context,
|
||||
},
|
||||
@ -140,12 +136,8 @@ export const createSlateObject = ({ slateId, data }) => {
|
||||
|
||||
const userProfileURL = `https://slate.host/${data.context.username}`;
|
||||
const userURL = `<${userProfileURL}|${data.context.username}>`;
|
||||
const objectURL = `<https://slate.host/${data.context.username}/${data.context.slatename}/cid:${
|
||||
data.context.cid
|
||||
}|${data.context.cid}>`;
|
||||
const message = `*${userURL}* added ${objectURL} to https://slate.host/${
|
||||
data.context.username
|
||||
}/${data.context.slatename}`;
|
||||
const objectURL = `<https://slate.host/${data.context.username}/${data.context.slatename}/cid:${data.context.cid}|${data.context.cid}>`;
|
||||
const message = `*${userURL}* added ${objectURL} to https://slate.host/${data.context.username}/${data.context.slatename}`;
|
||||
|
||||
Social.sendSlackMessage(message);
|
||||
} catch (e) {
|
||||
|
40
pages/api/activity/get.js
Normal file
40
pages/api/activity/get.js
Normal file
@ -0,0 +1,40 @@
|
||||
import * as Utilities from "~/node_common/utilities";
|
||||
import * as Data from "~/node_common/data";
|
||||
import * as Strings from "~/common/strings";
|
||||
|
||||
export default async (req, res) => {
|
||||
const id = Utilities.getIdFromCookie(req);
|
||||
if (!id) {
|
||||
return res.status(500).send({ decorator: "SERVER_GET_ACTIVITY", error: true });
|
||||
}
|
||||
|
||||
const user = await Data.getUserById({
|
||||
id,
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).send({
|
||||
decorator: "SERVER_GET_ACTIVITY_USER_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (user.error) {
|
||||
return res.status(500).send({
|
||||
decorator: "SERVER_GET_ACTIVITY_USER_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
let response = await Data.getActivityForUserId({ userId: user.id });
|
||||
|
||||
if (!response) {
|
||||
return res.status(404).send({ decorator: "SERVER_GET_ACTIVITY_NOT_FOUND", error: true });
|
||||
}
|
||||
|
||||
if (response.error) {
|
||||
return res.status(500).send({ decorator: "SERVER_GET_ACTIVITY_NOT_FOUND", error: true });
|
||||
}
|
||||
|
||||
return res.status(200).send({ decorator: "SERVER_GET_SLATE", activity: response });
|
||||
};
|
@ -85,10 +85,25 @@ export default async (req, res) => {
|
||||
data: {
|
||||
actorUserId: user.id,
|
||||
context: {
|
||||
username: user.username,
|
||||
slatename: slate.slatename,
|
||||
url,
|
||||
cid,
|
||||
slate: {
|
||||
id: slate.id,
|
||||
slatename: slate.slatename,
|
||||
name: slate.data.name,
|
||||
},
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
photo: user.data.photo,
|
||||
},
|
||||
file: {
|
||||
blurhash: each.blurhash,
|
||||
id: each.id,
|
||||
url,
|
||||
cid,
|
||||
type: each.type,
|
||||
name: each.name,
|
||||
title: each.title,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -79,7 +79,18 @@ export default async (req, res) => {
|
||||
userId: user.id,
|
||||
data: {
|
||||
actorUserId: user.id,
|
||||
context: { id: user.id, username: user.username, slatename: slate.slatename },
|
||||
context: {
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
photo: user.data.photo,
|
||||
},
|
||||
slate: {
|
||||
slatename: slate.slatename,
|
||||
id: slate.id,
|
||||
name: slate.data.name,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -1,10 +1,16 @@
|
||||
import * as React from "react";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as Validations from "~/common/validations";
|
||||
import * as Window from "~/common/window";
|
||||
import * as SVG from "~/common/svg";
|
||||
import * as Actions from "~/common/actions";
|
||||
import * as Events from "~/common/custom-events";
|
||||
import * as System from "~/components/system";
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
|
||||
import ScenePage from "~/components/core/ScenePage";
|
||||
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
|
||||
import DataView from "~/components/core/DataView";
|
||||
import ScenePageHeader from "~/components/core/ScenePageHeader";
|
||||
|
||||
@ -27,7 +33,178 @@ const STYLES_VIDEO_BIG = css`
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_IMAGE_BOX = css`
|
||||
cursor: pointer;
|
||||
${"" /* background-size: cover;
|
||||
background-position: 50% 50%; */}
|
||||
position: relative;
|
||||
box-shadow: ${Constants.shadow.light};
|
||||
margin: 10px;
|
||||
|
||||
:hover {
|
||||
box-shadow: ${Constants.shadow.medium};
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_PROFILE_IMAGE_BOX = css`
|
||||
background-size: cover;
|
||||
background-position: 50% 50%;
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 16px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
`;
|
||||
|
||||
const STYLES_SLATE_NAME = css`
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-family: ${Constants.font.medium};
|
||||
font-size: ${Constants.typescale.lvlN1};
|
||||
color: ${Constants.system.white};
|
||||
${"" /* text-shadow: 0px 0px 7px rgba(0, 0, 0, 0.5), 1px 1px 4px rgba(0, 0, 0, 0.1),
|
||||
-1px -1px 4px rgba(0, 0, 0, 0.1); */}
|
||||
`;
|
||||
|
||||
const STYLES_TITLE = css`
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: ${Constants.system.white};
|
||||
${"" /* text-shadow: 0px 0px 7px rgba(0, 0, 0, 0.5), 0px 0px 1px rgba(0, 0, 0, 0.3); */}
|
||||
`;
|
||||
|
||||
const STYLES_GRADIENT = css`
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 0, 0, 0) 0%,
|
||||
rgba(0, 0, 0, 0.2) 26.56%,
|
||||
rgba(0, 0, 0, 0.3) 100%
|
||||
);
|
||||
backdrop-filter: blur(2px);
|
||||
width: 100%;
|
||||
height: 72px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
`;
|
||||
|
||||
const ActivitySquare = ({ item, size }) => {
|
||||
return (
|
||||
<div css={STYLES_IMAGE_BOX} style={{ width: size, height: size }}>
|
||||
<SlateMediaObjectPreview
|
||||
centeredImage
|
||||
iconOnly
|
||||
blurhash={item.file.blurhash}
|
||||
url={item.file.url}
|
||||
title={item.file.title || item.file.name}
|
||||
type={item.file.type}
|
||||
style={{ border: "none" }}
|
||||
imageStyle={{ border: "none" }}
|
||||
/>
|
||||
<div css={STYLES_GRADIENT} />
|
||||
{/* <div css={STYLES_PROFILE_IMAGE_BOX} style={{ backgroundImage: `url(${item.user.photo})` }} /> */}
|
||||
<div css={STYLES_SLATE_NAME} style={{ width: size }}>
|
||||
<div
|
||||
style={{
|
||||
lineHeight: "12px",
|
||||
}}
|
||||
>
|
||||
{item.slate.name || item.slate.slatename}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ActivityRectangle = ({ item, size }) => {
|
||||
let file = item.slate?.objects?.length ? item.slate.objects[0] : null; //need to check if it's an image, go through and find one that works
|
||||
let numObjects = item.slate?.objects?.length || 0;
|
||||
return (
|
||||
<div css={STYLES_IMAGE_BOX} style={{ width: size * 2 + 10, height: size }}>
|
||||
<SlateMediaObjectPreview
|
||||
centeredImage
|
||||
iconOnly
|
||||
blurhash={file.blurhash}
|
||||
url={file.url}
|
||||
title={file.title || file.name}
|
||||
type={file.type}
|
||||
style={{ border: "none" }}
|
||||
imageStyle={{ border: "none" }}
|
||||
/>
|
||||
<div css={STYLES_GRADIENT} />
|
||||
{/* <div css={STYLES_PROFILE_IMAGE_BOX} style={{ backgroundImage: `url(${item.user.photo})` }} /> */}
|
||||
<div css={STYLES_TITLE} style={{ width: size }}>
|
||||
<div
|
||||
style={{
|
||||
lineHeight: "12px",
|
||||
fontFamily: Constants.font.semiBold,
|
||||
marginBottom: 8,
|
||||
}}
|
||||
>
|
||||
{item.slate.name || item.slate.slatename}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
lineHeight: "12px",
|
||||
fontFamily: Constants.font.medium,
|
||||
fontSize: Constants.typescale.lvlN1,
|
||||
color: Constants.system.textGrayLight,
|
||||
}}
|
||||
>
|
||||
{numObjects} File{numObjects == 1 ? "" : "s"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default class SceneHome extends React.Component {
|
||||
state = {
|
||||
imageSize: 200,
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
//only fetch the last x days worth of updates maybe? or last x entries of updates?
|
||||
//maybe do this when get viewer, not here. So that dont' redo every time you go back to this scene. Or maybe save it to viewer so you don't have to redo it?
|
||||
console.log(this.props.viewer.activity);
|
||||
this.calculateWidth();
|
||||
this.debounceInstance = Window.debounce(this.calculateWidth, 200);
|
||||
window.addEventListener("resize", this.debounceInstance);
|
||||
let activity = this.props.viewer.activity;
|
||||
let slateIds = [];
|
||||
if (activity && activity.length) {
|
||||
activity = activity.filter((item) => {
|
||||
if (item.data.type === "OTHER_USER_CREATE_SLATE") {
|
||||
slateIds.push(item.data.context.slate.id);
|
||||
}
|
||||
return (
|
||||
item.data.type === "OTHER_USER_CREATE_SLATE" ||
|
||||
item.data.type === "OTHER_USER_CREATE_SLATE_OBJECT"
|
||||
);
|
||||
});
|
||||
}
|
||||
let slates = await Actions.getSlatesByIds({ id: slateIds });
|
||||
console.log(slates);
|
||||
//match them up with the slates. add to a hashtable?
|
||||
//remove ones with no objects
|
||||
//reorder to get a nice ordering
|
||||
//maybe you try and fill a row. if it fails, you try and remove a "1" square from it and move that down to the next row
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("resize", this.debounceInstance);
|
||||
}
|
||||
|
||||
_handleCreateSlate = () => {
|
||||
this.props.onAction({
|
||||
type: "NAVIGATE",
|
||||
@ -36,27 +213,171 @@ export default class SceneHome extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let hasChildren = false;
|
||||
if (this.props.viewer && this.props.viewer.library[0].children.length) {
|
||||
hasChildren = true;
|
||||
calculateWidth = () => {
|
||||
let windowWidth = window.innerWidth;
|
||||
let imageSize;
|
||||
if (windowWidth < Constants.sizes.mobile) {
|
||||
imageSize = (windowWidth - 2 * 24 - 20) / 2;
|
||||
} else {
|
||||
imageSize = (windowWidth - 2 * 56 - 5 * 10) / 6;
|
||||
}
|
||||
this.setState({ imageSize });
|
||||
};
|
||||
|
||||
render() {
|
||||
let squareItem = {
|
||||
slate: {
|
||||
id: "6fef590d-6347-48bd-a262-d7fd09319c55",
|
||||
slatename: "playin-around",
|
||||
name: "Playin Around",
|
||||
},
|
||||
user: {
|
||||
id: "5172dd8b-6b11-40d3-8c9f-b4cbaa0eb8e7",
|
||||
username: "martina",
|
||||
photo:
|
||||
"https://slate.textile.io/ipfs/bafkreib2kqtibn3pt25gdmyufrsg6gnlv5iw5mncbyenfpgfwqgq5xtk3m",
|
||||
},
|
||||
file: {
|
||||
blurhash: null,
|
||||
id: "data-adae67cb-4bab-4ade-a136-2512aab47904",
|
||||
url:
|
||||
"https://slate.textile.io/ipfs/bafkreiajw7ucp354rb4utaryhqde4e6rn3ydyukhnwrom3wuf6hs6m7msu",
|
||||
cid: "bafkreiajw7ucp354rb4utaryhqde4e6rn3ydyukhnwrom3wuf6hs6m7msu",
|
||||
type: "image/jpeg",
|
||||
name: "IMG_299.jpg",
|
||||
title: "IMG_299.jpg",
|
||||
},
|
||||
};
|
||||
let rectItem = {
|
||||
user: {
|
||||
id: "ee4817fb-5b57-4a6c-b762-9127a2cdc04f",
|
||||
username: "tuna",
|
||||
photo:
|
||||
"https://bafybeiabcoa7egpafljp6rnfhdbz7ifhnc27hpocu7clgld5oxsbjjimri.ipfs.slate.textile.io",
|
||||
},
|
||||
slate: {
|
||||
slatename: "Ouroboros",
|
||||
id: "53548922-ba60-4dd4-8358-4a4aff9ba3f3",
|
||||
name: "ouroboros",
|
||||
objects: [
|
||||
{
|
||||
id: "data-adae67cb-4bab-4ade-a136-2512aab47904",
|
||||
name: "IMG_9173.jpg",
|
||||
ownerId: "3cad78ea-01ad-4c92-8983-a97524fb9e35",
|
||||
size: 1697947,
|
||||
title: "IMG_9173.jpg",
|
||||
type: "image/jpeg",
|
||||
url:
|
||||
"https://slate.textile.io/ipfs/bafybeie5pyqpddco6s6pq2wypkrxfbsqr4vec532tz6kaqwpe5cn3v2bu4",
|
||||
},
|
||||
{
|
||||
id: "data-b114d7e5-1092-4729-86c4-71a94ebe2215",
|
||||
name: "IMG_6730.jpg",
|
||||
ownerId: "3cad78ea-01ad-4c92-8983-a97524fb9e35",
|
||||
size: 2144037,
|
||||
title: "IMG_6730.jpg",
|
||||
type: "image/jpeg",
|
||||
url:
|
||||
"https://slate.textile.io/ipfs/bafybeih6ak5oufwhzqb5iuujukvmsnlitrhmhjds6dwkw5x6eqvxs3hke4",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
let squareItem2 = {
|
||||
slate: {
|
||||
id: "6fef590d-6347-48bd-a262-d7fd09319c55",
|
||||
slatename: "looper",
|
||||
name: "Looper",
|
||||
},
|
||||
user: {
|
||||
id: "5172dd8b-6b11-40d3-8c9f-b4cbaa0eb8e7",
|
||||
username: "martina",
|
||||
photo:
|
||||
"https://slate.textile.io/ipfs/bafkreifqrqyijknvg47uprc3rcjscavgesv6vuo7ypxwj27xqdi5aso6de",
|
||||
},
|
||||
file: {
|
||||
blurhash: null,
|
||||
id: "data-adae67cb-4bab-4ade-a136-2512aab47904",
|
||||
url:
|
||||
"https://slate.textile.io/ipfs/bafkreibh27gx3wmy4dxsl5px46mu4jjbemhlkbfuoszuro44atwznj7jqi",
|
||||
cid: "bafkreiajw7ucp354rb4utaryhqde4e6rn3ydyukhnwrom3wuf6hs6m7msu",
|
||||
type: "image/jpeg",
|
||||
name: "IMG_9173.jpg",
|
||||
title: "IMG_9173.jpg",
|
||||
},
|
||||
};
|
||||
let rectItem2 = {
|
||||
user: {
|
||||
id: "ee4817fb-5b57-4a6c-b762-9127a2cdc04f",
|
||||
username: "slate",
|
||||
photo:
|
||||
"https://slate.textile.io/ipfs/bafkreidc5he4qipe4dbentxtle5fao6kmeuwn7tujk5hdm7zqxc2a46uce",
|
||||
},
|
||||
slate: {
|
||||
slatename: "Maps of the world",
|
||||
id: "53548922-ba60-4dd4-8358-4a4aff9ba3f3",
|
||||
name: "maps-of-the-world",
|
||||
objects: [
|
||||
{
|
||||
id: "data-adae67cb-4bab-4ade-a136-2512aab47904",
|
||||
name: "IMG_9173.jpg",
|
||||
ownerId: "3cad78ea-01ad-4c92-8983-a97524fb9e35",
|
||||
size: 1697947,
|
||||
title: "IMG_9173.jpg",
|
||||
type: "image/jpeg",
|
||||
url:
|
||||
"https://slate.textile.io/ipfs/bafybeigesvxcebq4b4kggvnpmgdpuxowyackzrcbuujq6t75cy7e3o6u6u",
|
||||
},
|
||||
{
|
||||
id: "data-adae67cb-4bab-4ade-a136-2512aab47904",
|
||||
name: "IMG_9173.jpg",
|
||||
ownerId: "3cad78ea-01ad-4c92-8983-a97524fb9e35",
|
||||
size: 1697947,
|
||||
title: "IMG_9173.jpg",
|
||||
type: "image/jpeg",
|
||||
url:
|
||||
"https://slate.textile.io/ipfs/bafybeih6ak5oufwhzqb5iuujukvmsnlitrhmhjds6dwkw5x6eqvxs3hke4",
|
||||
},
|
||||
{
|
||||
id: "data-adae67cb-4bab-4ade-a136-2512aab47904",
|
||||
name: "IMG_9173.jpg",
|
||||
ownerId: "3cad78ea-01ad-4c92-8983-a97524fb9e35",
|
||||
size: 1697947,
|
||||
title: "IMG_9173.jpg",
|
||||
type: "image/jpeg",
|
||||
url:
|
||||
"https://slate.textile.io/ipfs/bafybeih6ak5oufwhzqb5iuujukvmsnlitrhmhjds6dwkw5x6eqvxs3hke4",
|
||||
},
|
||||
{
|
||||
id: "data-b114d7e5-1092-4729-86c4-71a94ebe2215",
|
||||
name: "IMG_6730.jpg",
|
||||
ownerId: "3cad78ea-01ad-4c92-8983-a97524fb9e35",
|
||||
size: 2144037,
|
||||
title: "IMG_6730.jpg",
|
||||
type: "image/jpeg",
|
||||
url:
|
||||
"https://slate.textile.io/ipfs/bafybeih6ak5oufwhzqb5iuujukvmsnlitrhmhjds6dwkw5x6eqvxs3hke4",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
//OTHER_USER_CREATE_SLATE and OTHER_USER_CREATE_SLATE_OBJECT are the ones you're looking for
|
||||
return (
|
||||
<ScenePage>
|
||||
<ScenePageHeader title="Home">
|
||||
{hasChildren
|
||||
? "Welcome back! Here is your data."
|
||||
{this.props.viewer.activity.length
|
||||
? null
|
||||
: "Welcome to Slate! You can share files with anyone in the world. Here is how it works:"}
|
||||
</ScenePageHeader>
|
||||
|
||||
{hasChildren ? (
|
||||
<div style={{ marginTop: "48px" }}>
|
||||
<DataView
|
||||
viewer={this.props.viewer}
|
||||
items={this.props.viewer.library[0].children}
|
||||
onAction={this.props.onAction}
|
||||
/>
|
||||
{this.props.viewer.activity.length ? (
|
||||
<div
|
||||
style={{ margin: "-10px", marginTop: "38px", display: "flex", flexDirection: "row" }}
|
||||
>
|
||||
<ActivitySquare size={this.state.imageSize} item={squareItem} />
|
||||
<ActivityRectangle size={this.state.imageSize} item={rectItem} />
|
||||
<ActivityRectangle size={this.state.imageSize} item={rectItem2} />
|
||||
<ActivitySquare size={this.state.imageSize} item={squareItem2} />
|
||||
</div>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
|
Loading…
Reference in New Issue
Block a user