1
0
mirror of https://github.com/barthuijgen/factorio-sites.git synced 2024-12-04 10:44:44 +02:00

Added ability to add and remove user favorites on the main page (#77)

* Added ability to add and remove user favorites on the main page

* Style fixes

* Fix pagination and list reload
This commit is contained in:
Alexander Horbunov 2021-03-29 01:09:48 +03:00 committed by GitHub
parent 6166e81c19
commit b2a3264049
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 136 additions and 18 deletions

View File

@ -5,12 +5,18 @@ import { css } from "@emotion/react";
import { Box, Text } from "@chakra-ui/react";
import { MdFavorite } from "react-icons/md";
import { BlueprintPage } from "@factorio-sites/types";
import clsx from "clsx";
const linkStyles = css`
margin: 5px 10px 5px 0;
background: #353535;
background: #403f40;
width: 210px;
height: 232px;
height: 255px;
box-shadow: inset 3px 0 3px -3px #201815, inset 2px 0 2px -2px #201815,
inset 1px 0 1px -1px #201815, inset 0 3px 3px -3px #8f8c8b, inset 0 2px 2px -2px #8f8c8b,
inset 0 1px 1px -1px #8f8c8b, inset -3px 0 3px -3px #201815, inset -2px 0 2px -2px #201815,
inset -2px 0 1px -1px #201815, inset 0 -3px 3px -3px #000, inset 0 -2px 2px -2px #000,
inset 0 -1px 1px -1px #000, 0 0 2px 0 #201815, 0 0 4px 0 #201815;
.block {
display: flex;
@ -20,12 +26,45 @@ const linkStyles = css`
.image {
position: relative;
width: 200px;
width: 190px;
height: 200px;
background: #303030;
margin: 10px;
box-shadow: inset 0 0 3px 0 #000, 0 -2px 2px -1px #000, -2px 0 2px -2px #28221f,
-2px 0 2px -2px #28221f, 2px 0 2px -2px #28221f, 2px 0 2px -2px #28221f,
0 3px 3px -3px #8f8c8b, 0 2px 2px -2px #8f8c8b, 0 1px 1px -1px #8f8c8b;
& > div {
margin: 2px !important;
}
}
.details {
display: flex;
margin: 0 10px;
padding: 0 5px;
background-color: #242324;
box-shadow: inset 0 0 3px 0 #000, 0 -2px 2px -1px #000, -2px 0 2px -2px #28221f,
-2px 0 2px -2px #28221f, 2px 0 2px -2px #28221f, 2px 0 2px -2px #28221f,
0 3px 3px -3px #8f8c8b, 0 2px 2px -2px #8f8c8b, 0 1px 1px -1px #8f8c8b;
}
.favorite {
margin-right: 5px;
&.user-favorite svg {
fill: #fe5a5a;
}
&:hover {
cursor: pointer;
opacity: 0.7;
}
&:disabled {
pointer-events: none;
}
}
.title {
@ -36,7 +75,7 @@ const linkStyles = css`
a {
display: block;
padding: 5px;
/* padding: 5px; */
color: #fff;
}
@ -47,11 +86,23 @@ const linkStyles = css`
`;
interface BlueprintTileProps {
blueprint: Pick<BlueprintPage, "id" | "title" | "image_hash" | "favorite_count" | "updated_at">;
blueprint: Pick<
BlueprintPage,
"id" | "title" | "image_hash" | "favorite_count" | "updated_at"
> & {
user_favorite: boolean;
};
editLink?: boolean;
disableFavorite?: boolean;
onFavoriteClick?: (id: string) => void;
}
export const BlueprintTile: React.FC<BlueprintTileProps> = ({ blueprint, editLink }) => {
export const BlueprintTile: React.FC<BlueprintTileProps> = ({
blueprint,
editLink,
disableFavorite,
onFavoriteClick,
}) => {
const [imageError, setImageError] = useState(false);
const onImageError = () => {
setImageError(true);
@ -81,7 +132,17 @@ export const BlueprintTile: React.FC<BlueprintTileProps> = ({ blueprint, editLin
</div>
<Box className="details">
<Text css={{ display: "flex", alignItems: "center", marginRight: "1rem" }}>
<MdFavorite css={{ marginRight: "5px" }} />
<button
className={clsx("favorite", { "user-favorite": blueprint.user_favorite })}
title={blueprint.user_favorite ? "Remove from favorites" : "Add to favorites"}
disabled={disableFavorite}
onClick={(e) => {
e.preventDefault();
onFavoriteClick?.(blueprint.id);
}}
>
<MdFavorite />
</button>
{blueprint.favorite_count || "0"}
</Text>
<Text className="title">{blueprint.title}</Text>

View File

@ -1,7 +1,11 @@
import React, { useEffect, useState } from "react";
import { NextPage, NextPageContext } from "next";
import { NextPage } from "next";
import { useRouter } from "next/router";
import { searchBlueprintPages, init } from "@factorio-sites/database";
import {
searchBlueprintPages,
init,
getUserFavoriteBlueprintPages,
} from "@factorio-sites/database";
import { BlueprintPage } from "@factorio-sites/types";
import { Panel } from "../components/Panel";
import { Pagination } from "../components/Pagination";
@ -26,6 +30,8 @@ import { css } from "@emotion/react";
import { MdSearch } from "react-icons/md";
import { TAGS } from "@factorio-sites/common-utils";
import { mq } from "@factorio-sites/web-utils";
import { useAuth } from "../providers/auth";
import { pageHandler } from "../utils/page-handler";
const pageCss = css({
display: "flex",
@ -60,24 +66,30 @@ const sidebarCheckbox = css(SidebarRow, {
},
});
type BlueprintPageWithUserFavorite = Pick<
BlueprintPage,
"id" | "image_hash" | "favorite_count" | "title" | "updated_at"
> & {
user_favorite: boolean;
};
interface IndexProps {
totalItems: number;
currentPage: number;
totalPages: number;
blueprints: Pick<
BlueprintPage,
"id" | "image_hash" | "favorite_count" | "title" | "updated_at"
>[];
blueprints: BlueprintPageWithUserFavorite[];
}
export const Index: NextPage<IndexProps> = ({
totalItems,
currentPage,
totalPages,
blueprints,
blueprints: blueprintsProp,
}) => {
const router = useRouter();
const auth = useAuth();
const [searchQuery, setSearchQuery] = useState("");
const [blueprints, setBlueprints] = useState<BlueprintPageWithUserFavorite[]>([]);
const routerQueryToHref = useRouterQueryToHref();
const data = useFbeData();
@ -85,6 +97,10 @@ export const Index: NextPage<IndexProps> = ({
setSearchQuery((router.query.q as string) || "");
}, [router?.query.q]);
useEffect(() => {
setBlueprints(blueprintsProp);
}, [blueprintsProp]);
if (!data) return null;
const entityOptions = Object.keys(data.entities).filter(
@ -97,6 +113,30 @@ export const Index: NextPage<IndexProps> = ({
value: tag.value,
}));
const handleBlueprintFavoriteClick = async (blueprint_page_id: string) => {
try {
const response = await fetch("/api/user/favorite", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ blueprint_page_id }),
});
const { favorite } = await response.json();
setBlueprints((blueprints) =>
blueprints.map((bp) =>
bp.id === blueprint_page_id
? {
...bp,
user_favorite: favorite,
favorite_count: bp.favorite_count + (favorite ? 1 : -1),
}
: bp
)
);
} catch (err) {
console.error(err);
}
};
return (
<SimpleGrid columns={1}>
<Panel title="Blueprints">
@ -197,7 +237,14 @@ export const Index: NextPage<IndexProps> = ({
<Box css={{ display: "flex", flexDirection: "column" }}>
<Box css={{ display: "flex", flexWrap: "wrap", minHeight: "400px", flexGrow: 1 }}>
{blueprints.length ? (
blueprints.map((bp) => <BlueprintTile key={bp.id} blueprint={bp} />)
blueprints.map((bp) => (
<BlueprintTile
key={bp.id}
blueprint={bp}
disableFavorite={!auth}
onFavoriteClick={handleBlueprintFavoriteClick}
/>
))
) : (
<p css={{ marginTop: "10px" }}>No results found</p>
)}
@ -212,7 +259,7 @@ export const Index: NextPage<IndexProps> = ({
);
};
export async function getServerSideProps({ query }: NextPageContext) {
export const getServerSideProps = pageHandler(async ({ query }, { session }) => {
await init();
const page = Number(query.page || "1");
const perPage = Number(query["per-page"] || "20");
@ -241,6 +288,14 @@ export async function getServerSideProps({ query }: NextPageContext) {
user,
absolute_snapping,
});
const userFavorites: string[] = session?.user_id
? (
await getUserFavoriteBlueprintPages(
session.user_id,
rows.map((row) => row.id)
)
).map((item) => item.id)
: [];
return {
props: {
@ -253,9 +308,10 @@ export async function getServerSideProps({ query }: NextPageContext) {
favorite_count: row.favorite_count,
title: row.title,
updated_at: row.updated_at,
user_favorite: userFavorites.includes(row.id),
})),
} as IndexProps,
};
}
});
export default Index;

View File

@ -55,12 +55,13 @@ export async function getBlueprintPageByFactorioprintsId(
return result ? mapBlueprintPageEntityToObject(result) : null;
}
export async function getUserFavoriteBlueprintPages(user_id: string) {
export async function getUserFavoriteBlueprintPages(user_id: string, ids?: string[]) {
const result = await prisma.blueprint_page.findMany({
where: {
user_favorites: {
some: {
user_id: user_id,
blueprint_page_id: ids ? { in: ids } : undefined,
},
},
},