feat(activity): show owner info in CollectionPreviewBlock

This commit is contained in:
Aminejv 2021-07-15 17:32:18 +01:00
parent 1cfabf7f5e
commit 5eac0f1a9f
14 changed files with 174 additions and 51 deletions

View File

@ -216,3 +216,6 @@ export const grids = {
mobile: { width: 344, rowGap: 8 },
},
};
export const profileDefaultPicture =
"https://slate.textile.io/ipfs/bafkreick3nscgixwfpq736forz7kzxvvhuej6kszevpsgmcubyhsx2pf7i";

View File

@ -71,7 +71,12 @@ export default function ActivityCollectionGroup({
<div css={Styles.COLLECTIONS_PREVIEW_GRID}>
{elements.map((collection) => (
<Link key={collection.id} href={`/$/slate/${collection.id}`} onAction={onAction}>
<CollectionPreviewBlock collection={collection} viewer={viewer} />
<CollectionPreviewBlock
collection={collection}
viewer={viewer}
owner={collection.owner}
onAction={onAction}
/>
</Link>
))}
{showMore &&
@ -84,12 +89,22 @@ export default function ActivityCollectionGroup({
key={collection.id}
>
<Link key={collection.id} href={`/$/slate/${collection.id}`} onAction={onAction}>
<CollectionPreviewBlock collection={collection} viewer={viewer} />
<CollectionPreviewBlock
collection={collection}
viewer={viewer}
owner={collection.owner}
onAction={onAction}
/>
</Link>
</motion.div>
) : (
<Link key={collection.id} href={`/$/slate/${collection.id}`} onAction={onAction}>
<CollectionPreviewBlock collection={collection} viewer={viewer} />
<CollectionPreviewBlock
collection={collection}
viewer={viewer}
owner={collection.owner}
onAction={onAction}
/>
</Link>
)
)}

View File

@ -2,6 +2,7 @@ import * as React from "react";
import * as Styles from "~/common/styles";
import * as Utilities from "~/common/utilities";
import * as Strings from "~/common/strings";
import * as Constants from "~/common/constants";
import { Link } from "~/components/core/Link";
import { css } from "@emotion/react";
@ -58,7 +59,12 @@ export default function ProfileInfo({ owner, viewer, time, action, onAction }) {
return (
<Link href={`/$/user/${owner.id}`} onAction={onAction}>
<div css={STYLES_PROFILE_CONTAINER}>
<img src={photo} alt={`${username} profile`} css={STYLES_PROFILE} />
<img
src={photo}
alt={`${username} profile`}
css={STYLES_PROFILE}
onError={(e) => (e.target.src = Constants.profileDefaultPicture)}
/>
<div css={STYLES_MOBILE_ALIGN}>
<span>
<H4 color="textBlack" css={[STYLES_TEXT_BLACK, Styles.HEADING_04]}>

View File

@ -2,6 +2,7 @@ import * as React from "react";
import * as Strings from "~/common/strings";
import * as Typography from "~/components/system/components/Typography";
import * as Styles from "~/common/styles";
import * as Constants from "~/common/constants";
import { Divider } from "~/components/system/components/Divider";
import { Logo } from "~/common/logo";
@ -10,6 +11,7 @@ import { LikeButton, SaveButton } from "~/components/core/ObjectPreview/componen
import { useLikeHandler, useSaveHandler } from "~/common/hooks";
import { FollowButton } from "~/components/core/CollectionPreviewBlock/components";
import { useFollowHandler } from "~/components/core/CollectionPreviewBlock/hooks";
import { Link } from "~/components/core/Link";
import ObjectPlaceholder from "~/components/core/ObjectPreview/placeholders";
@ -152,7 +154,7 @@ const useCollectionCarrousel = ({ objects }) => {
return { selectBatchIdx, selectedBatch, selectedIdx };
};
export default function CollectionPreview({ collection, viewer }) {
export default function CollectionPreview({ collection, viewer, owner, onAction }) {
const { follow, followCount, isFollowed } = useFollowHandler({ collection, viewer });
const filePreviews = React.useMemo(() => {
const files = collection?.objects || [];
@ -242,16 +244,34 @@ export default function CollectionPreview({ collection, viewer }) {
{followCount}
</Typography.P1>
</div>
<div css={Styles.CONTAINER_CENTERED}>
<img
css={STYLES_PROFILE_IMAGE}
src="https://slate.textile.io/ipfs/bafkreick3nscgixwfpq736forz7kzxvvhuej6kszevpsgmcubyhsx2pf7i"
alt="owner profile"
/>
<Typography.P2 style={{ marginLeft: 8 }} color="textGrayDark">
Wes Anderson
</Typography.P2>
</div>
{owner && (
<div style={{ alignItems: "end" }} css={Styles.CONTAINER_CENTERED}>
<Link
href={`/$/user/${owner.id}`}
onAction={onAction}
aria-label={`Visit ${owner.username}'s profile`}
title={`Visit ${owner.username}'s profile`}
>
<img
css={STYLES_PROFILE_IMAGE}
src={owner.data.photo}
alt={`${owner.username} profile`}
onError={(e) => (e.target.src = Constants.profileDefaultPicture)}
/>
</Link>
<Link
href={`/$/user/${owner.id}`}
onAction={onAction}
aria-label={`Visit ${owner.username}'s profile`}
title={`Visit ${owner.username}'s profile`}
>
<Typography.P2 style={{ marginLeft: 8 }} color="textGrayDark">
{owner.username}
</Typography.P2>
</Link>
</div>
)}
</div>
</div>
</div>

View File

@ -2,6 +2,7 @@ import * as React from "react";
import * as Strings from "~/common/strings";
import * as Typography from "~/components/system/components/Typography";
import * as Styles from "~/common/styles";
import * as Constants from "~/common/constants";
import { useInView } from "~/common/hooks";
import { isBlurhashValid } from "blurhash";
@ -9,6 +10,7 @@ import { Blurhash } from "react-blurhash";
import { css } from "@emotion/react";
import { FollowButton } from "~/components/core/CollectionPreviewBlock/components";
import { useFollowHandler } from "~/components/core/CollectionPreviewBlock/hooks";
import { Link } from "~/components/core/Link";
const STYLES_CONTAINER = (theme) => css`
display: flex;
@ -129,7 +131,7 @@ const useCollectionCarrousel = ({ objects }) => {
};
};
export default function ImageCollectionPreview({ collection, viewer }) {
export default function ImageCollectionPreview({ collection, viewer, owner, onAction }) {
const { follow, followCount, isFollowed } = useFollowHandler({ collection, viewer });
const filePreviews = React.useMemo(() => {
@ -147,14 +149,8 @@ export default function ImageCollectionPreview({ collection, viewer }) {
ref: previewerRef,
});
const {
isLoaded,
blurhash,
selectedImage,
handleLoading,
selectedIdx,
selectImageByIdx,
} = useCollectionCarrousel({ objects: filePreviews });
const { isLoaded, blurhash, selectedImage, handleLoading, selectedIdx, selectImageByIdx } =
useCollectionCarrousel({ objects: filePreviews });
const nbrOfFiles = collection?.objects?.length || 0;
@ -218,16 +214,33 @@ export default function ImageCollectionPreview({ collection, viewer }) {
{followCount}
</Typography.P1>
</div>
<div css={Styles.CONTAINER_CENTERED}>
<img
css={STYLES_PROFILE_IMAGE}
src="https://slate.textile.io/ipfs/bafkreick3nscgixwfpq736forz7kzxvvhuej6kszevpsgmcubyhsx2pf7i"
alt="owner profile"
/>
<Typography.P2 style={{ marginLeft: 8 }} color="textGrayDark">
Wes Anderson
</Typography.P2>
</div>
{owner && (
<div style={{ alignItems: "end" }} css={Styles.CONTAINER_CENTERED}>
<Link
href={`/$/user/${owner.id}`}
onAction={onAction}
aria-label={`Visit ${owner.username}'s profile`}
title={`Visit ${owner.username}'s profile`}
>
<img
css={STYLES_PROFILE_IMAGE}
src={owner.data.photo}
alt={`${owner.username} profile`}
onError={(e) => (e.target.src = Constants.profileDefaultPicture)}
/>
</Link>
<Link
href={`/$/user/${owner.id}`}
onAction={onAction}
aria-label={`Visit ${owner.username}'s profile`}
title={`Visit ${owner.username}'s profile`}
>
<Typography.P2 style={{ marginLeft: 8 }} color="textGrayDark">
{owner.username}
</Typography.P2>
</Link>
</div>
)}
</div>
</div>
</div>

View File

@ -4,14 +4,28 @@ import * as Validations from "~/common/validations";
import ImageCollectionPreview from "./ImageCollectionPreview";
import FilesCollectionPreview from "./FilesCollectionPreview";
export default function CollectionPreview({ collection, viewer }) {
export default function CollectionPreview({ collection, viewer, owner, onAction }) {
const objects = collection.objects.filter((file) =>
Validations.isPreviewableImage(file.data.type)
);
if (objects.length > 0) {
return <ImageCollectionPreview collection={{ ...collection, objects }} viewer={viewer} />;
return (
<ImageCollectionPreview
collection={{ ...collection, objects }}
viewer={viewer}
owner={owner}
onAction={onAction}
/>
);
}
return <FilesCollectionPreview collection={collection} viewer={viewer} />;
return (
<FilesCollectionPreview
collection={collection}
viewer={viewer}
owner={owner}
onAction={onAction}
/>
);
}

View File

@ -159,6 +159,7 @@ export default function ObjectPreviewPremitive({
css={STYLES_PROFILE_IMAGE}
src={owner.data.photo}
alt={`${owner.username} profile`}
onError={(e) => (e.target.src = Constants.profileDefaultPicture)}
/>
</Link>
)}

View File

@ -354,7 +354,7 @@ function CollectionsPage({
onAction={onAction}
collection={collection}
viewer={viewer}
owner={user}
owner={tab === "collections" ? user : collection.owner}
/>
</Link>
))}

View File

@ -2,6 +2,7 @@ import * as React from "react";
import * as Styles from "~/common/styles";
import * as Typography from "~/components/system/components/Typography";
import * as Strings from "~/common/strings";
import * as Constants from "~/common/constants";
import { Divider } from "~/components/system/components/Divider";
import { Logo } from "~/common/logo";
@ -142,7 +143,12 @@ export default function ProfilePreviewBlock({ onAction, viewer, profile }) {
return (
<div css={STYLES_CONTAINER}>
<div css={[STYLES_PROFILE_DESCRIPTION, Styles.HORIZONTAL_CONTAINER]}>
<img css={STYLES_PROFILE_PREVIEW} src={profile.data.photo} alt={`${profile.username}`} />
<img
css={STYLES_PROFILE_PREVIEW}
src={profile.data.photo}
alt={`${profile.username}`}
onError={(e) => (e.target.src = Constants.profileDefaultPicture)}
/>
<div style={{ marginLeft: 16 }} css={Styles.VERTICAL_CONTAINER}>
<div>
<Typography.H4>{profile.username}</Typography.H4>

View File

@ -30,8 +30,20 @@ export default async ({
const slateFilesFields = ["files", "slate_files.createdAt", "files.id", "objects"];
const slateFilesQuery = `coalesce(json_agg(?? order by ?? asc) filter (where ?? is not null), '[]') as ??`;
const slateFields = [
const slateOwnerFields = [
"slate_table",
"slate_with_objects.*",
...Constants.userPreviewProperties,
"owner",
"slate_with_objects",
"users",
"slate_with_objects.ownerId",
"users.id",
];
const slateOwnerQuery = `?? as (SELECT ??, json_build_object('id', ??, 'data', ??, 'username', ??) as ?? FROM ?? LEFT JOIN ?? ON ?? = ?? ) `;
const slateFields = [
"slate_with_objects",
"slates.id",
"slates.slatename",
"slates.data",
@ -48,11 +60,13 @@ export default async ({
"files.id",
"slate_files.fileId",
"slates.id",
...slateOwnerFields,
];
const slateQuery = `WITH ?? as (SELECT ??, ??, ??, ??, ??, ??, ??, ${slateFilesQuery} FROM ?? LEFT JOIN ?? on ?? = ?? LEFT JOIN ?? on ?? = ?? GROUP BY ??)`;
const slateQuery = `WITH ?? as (SELECT ??, ??, ??, ??, ??, ??, ??, ${slateFilesQuery} FROM ?? LEFT JOIN ?? on ?? = ?? LEFT JOIN ?? on ?? = ?? GROUP BY ??), ${slateOwnerQuery}`;
const userFilesFields = ["files", "files.createdAt", "files.id", "objects"];
const userFilesQuery = `coalesce(json_agg(?? order by ?? asc) filter (where ?? is not null), '[]') as ??`;
const userFields = [
"user_table",
"users.id",

View File

@ -6,8 +6,20 @@ export default async ({ earliestTimestamp, latestTimestamp }) => {
const slateFilesFields = ["files", "slate_files.createdAt", "files.id", "objects"];
const slateFilesQuery = `coalesce(json_agg(?? order by ?? asc) filter (where ?? is not null), '[]') as ??`;
const slateFields = [
const slateOwnerFields = [
"slate_table",
"slate_with_objects.*",
...Constants.userPreviewProperties,
"owner",
"slate_with_objects",
"users",
"slate_with_objects.ownerId",
"users.id",
];
const slateOwnerQuery = `?? as (SELECT ??, json_build_object('id', ??, 'data', ??, 'username', ??) as ?? FROM ?? LEFT JOIN ?? ON ?? = ?? ) `;
const slateFields = [
"slate_with_objects",
"slates.id",
"slates.slatename",
"slates.data",
@ -24,11 +36,13 @@ export default async ({ earliestTimestamp, latestTimestamp }) => {
"files.id",
"slate_files.fileId",
"slates.id",
...slateOwnerFields,
];
const slateQuery = `WITH ?? as (SELECT ??, ??, ??, ??, ??, ??, ??, ${slateFilesQuery} FROM ?? LEFT JOIN ?? on ?? = ?? LEFT JOIN ?? on ?? = ?? GROUP BY ??)`;
const slateQuery = `WITH ?? as (SELECT ??, ??, ??, ??, ??, ??, ??, ${slateFilesQuery} FROM ?? LEFT JOIN ?? on ?? = ?? LEFT JOIN ?? on ?? = ?? GROUP BY ??), ${slateOwnerQuery}`;
const userFilesFields = ["files", "files.createdAt", "files.id", "objects"];
const userFilesQuery = `coalesce(json_agg(?? order by ?? asc) filter (where ?? is not null), '[]') as ??`;
const userFields = [
"user_table",
"users.id",

View File

@ -11,6 +11,12 @@ export default async ({ ownerId }) => {
// const slateFiles = () =>
// DB.raw("json_agg(?? order by ?? asc) as ??", ["files", "slate_files.createdAt", "objects"]);
const ownerQueryFields = ["*", ...Constants.userPreviewProperties, "owner"];
const ownerQuery = DB.raw(
`??, json_build_object('id', ??, 'data', ??, 'username', ??) as ??`,
ownerQueryFields
);
const slateFiles = () =>
DB.raw("coalesce(json_agg(?? order by ?? asc) filter (where ?? is not null), '[]') as ??", [
"files",
@ -19,14 +25,20 @@ export default async ({ ownerId }) => {
"objects",
]);
const query = await DB.select(...Serializers.slateProperties, slateFiles())
const query = await DB.with("slates", (db) =>
db
.select(...Serializers.slateProperties, slateFiles())
.from("slates")
.join("subscriptions", "subscriptions.slateId", "=", "slates.id")
.join("slate_files", "slate_files.slateId", "=", "slates.id")
.join("files", "slate_files.fileId", "=", "files.id")
.where({ "subscriptions.ownerId": ownerId, "slates.isPublic": true })
// .orderBy("subscriptions.createdAt", "desc");
.groupBy("slates.id")
)
.select(ownerQuery)
.from("slates")
.join("subscriptions", "subscriptions.slateId", "=", "slates.id")
.join("slate_files", "slate_files.slateId", "=", "slates.id")
.join("files", "slate_files.fileId", "=", "files.id")
.where({ "subscriptions.ownerId": ownerId, "slates.isPublic": true })
// .orderBy("subscriptions.createdAt", "desc");
.groupBy("slates.id");
.join("users", "slates.ownerId", "users.id");
if (!query || query.error) {
return [];
@ -39,7 +51,7 @@ export default async ({ ownerId }) => {
return JSON.parse(JSON.stringify(serialized));
},
errorFn: async (e) => {
errorFn: async () => {
Logging.error({
error: true,
decorator: "GET_SUBSCRIPTIONS_BY_USER_ID",

View File

@ -31,6 +31,7 @@ export const sanitizeSlate = (entity) => {
ownerId: entity.ownerId,
isPublic: entity.isPublic,
objects: entity.objects,
owner: entity.owner,
user: entity.user, //NOTE(martina): this is not in the database. It is added after
data: {
name: entity.data?.name,

View File

@ -72,6 +72,8 @@ export default class SceneSlates extends React.Component {
key={slate.id}
collection={slate}
viewer={this.props.viewer}
owner={this.props.viewer}
onAction={this.props.onAction}
/>
</Link>
))}
@ -101,7 +103,9 @@ export default class SceneSlates extends React.Component {
<CollectionPreviewBlock
key={slate.id}
collection={slate}
owner={slate.owner}
viewer={this.props.viewer}
onAction={this.props.onAction}
/>
</Link>
))}