mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-30 23:27:55 -05:00
can edit builds
This commit is contained in:
2
TODO.md
2
TODO.md
@@ -1,7 +1,7 @@
|
||||
### Before production
|
||||
|
||||
- [x] Can log in
|
||||
- [ ] Can update builds
|
||||
- [x] Can update builds
|
||||
- [ ] Build Analyzer
|
||||
- [ ] Import /analyzer
|
||||
- [ ] Builds link to /analyzer
|
||||
|
||||
@@ -18,7 +18,7 @@ import { useMyTheme } from "lib/useMyTheme";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { FiBarChart2, FiInfo, FiTarget } from "react-icons/fi";
|
||||
import { FiBarChart2, FiEdit, FiInfo, FiTarget } from "react-icons/fi";
|
||||
import Gears from "./Gears";
|
||||
import ViewAP from "./ViewAP";
|
||||
import ViewSlots from "./ViewSlots";
|
||||
@@ -26,17 +26,15 @@ import ViewSlots from "./ViewSlots";
|
||||
interface BuildCardProps {
|
||||
// TODO: don't select unnecessary fields
|
||||
build: PartialBy<Prisma.BuildGetPayload<{ include: { user: true } }>, "user">;
|
||||
canModify?: boolean;
|
||||
//setBuildBeingEdited?: (build: Build) => void;
|
||||
otherBuildCount?: number;
|
||||
onShowAllByUser?: () => void;
|
||||
onEdit?: (build: BuildCardProps["build"]) => void;
|
||||
showWeapon?: boolean;
|
||||
}
|
||||
|
||||
const BuildCard: React.FC<BuildCardProps & BoxProps> = ({
|
||||
build,
|
||||
canModify,
|
||||
//setBuildBeingEdited,
|
||||
onEdit,
|
||||
otherBuildCount,
|
||||
onShowAllByUser,
|
||||
showWeapon,
|
||||
@@ -159,20 +157,17 @@ const BuildCard: React.FC<BuildCardProps & BoxProps> = ({
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)}
|
||||
{/* {canModify && (
|
||||
{onEdit && (
|
||||
<IconButton
|
||||
variant="ghost"
|
||||
isRound
|
||||
colorScheme={themeColor}
|
||||
onClick={
|
||||
setBuildBeingEdited && (() => setBuildBeingEdited(build))
|
||||
}
|
||||
aria-label="Show description"
|
||||
onClick={() => onEdit(build)}
|
||||
aria-label="Edit build"
|
||||
fontSize="20px"
|
||||
icon={<FiEdit />}
|
||||
ml="0.5em"
|
||||
/>
|
||||
)} */}
|
||||
)}
|
||||
</Flex>
|
||||
<Box mt="1em">
|
||||
<Gears build={build} />
|
||||
|
||||
@@ -93,7 +93,11 @@ const BuildModal: React.FC<Props> = ({ onClose, build }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const success = await sendData("POST", "/api/builds", mutationData);
|
||||
const success = await sendData(
|
||||
build ? "PUT" : "POST",
|
||||
"/api/builds",
|
||||
build ? { ...mutationData, id: build.id } : mutationData
|
||||
);
|
||||
setSending(false);
|
||||
if (!success) return;
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ export const buildSchema = z.object({
|
||||
.refine((val) => !val || shoesGear.includes(val as any))
|
||||
.optional()
|
||||
.nullable(),
|
||||
id: z.number().optional(),
|
||||
});
|
||||
|
||||
function isAbilityArray(arr: any[], type: "HEAD" | "CLOTHING" | "SHOES") {
|
||||
|
||||
@@ -8,11 +8,7 @@ import DBClient from "prisma/client";
|
||||
|
||||
const prisma = DBClient.getInstance().prisma;
|
||||
|
||||
const buildHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).end();
|
||||
}
|
||||
|
||||
const postHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const user = await getMySession(req);
|
||||
if (!user) return res.status(401).end();
|
||||
|
||||
@@ -33,23 +29,6 @@ const buildHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
.json({ message: "You have too many builds posted already" });
|
||||
}
|
||||
|
||||
const getAbilityPoints = () => {
|
||||
const result: Partial<Record<Ability, number>> = {};
|
||||
|
||||
const getPointsFromAbilityArray = (ability: Ability, index: number) => {
|
||||
const existingAmount = result[ability] ?? 0;
|
||||
const apsToAdd = index === 0 ? 10 : 3;
|
||||
|
||||
result[ability] = existingAmount + apsToAdd;
|
||||
};
|
||||
|
||||
parsed.data.headAbilities.forEach(getPointsFromAbilityArray);
|
||||
parsed.data.clothingAbilities.forEach(getPointsFromAbilityArray);
|
||||
parsed.data.shoesAbilities.forEach(getPointsFromAbilityArray);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const hasTop500WithTheWeapon = async () => {
|
||||
const playerData = await prisma.player.findFirst({
|
||||
where: { userId: user.id },
|
||||
@@ -70,7 +49,11 @@ const buildHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
await prisma.build.create({
|
||||
data: {
|
||||
...parsed.data,
|
||||
abilityPoints: getAbilityPoints(),
|
||||
abilityPoints: getAbilityPoints(
|
||||
parsed.data.headAbilities,
|
||||
parsed.data.clothingAbilities,
|
||||
parsed.data.shoesAbilities
|
||||
),
|
||||
jpn: postsJpBuilds,
|
||||
top500: await hasTop500WithTheWeapon(),
|
||||
user: {
|
||||
@@ -84,4 +67,79 @@ const buildHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
res.status(200).end();
|
||||
};
|
||||
|
||||
const updateHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const user = await getMySession(req);
|
||||
if (!user) return res.status(401).end();
|
||||
|
||||
const parsed = buildSchema.safeParse(req.body);
|
||||
|
||||
if (!parsed.success) {
|
||||
return res.status(400).end();
|
||||
}
|
||||
|
||||
const id = parsed.data.id;
|
||||
|
||||
const existingBuild = await prisma.build.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
if (!existingBuild || existingBuild.weapon !== parsed.data.weapon) {
|
||||
return res.status(400).end();
|
||||
}
|
||||
|
||||
if (existingBuild.userId !== user.id) {
|
||||
return res.status(403).end();
|
||||
}
|
||||
|
||||
delete parsed.data.id;
|
||||
|
||||
await prisma.build.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...parsed.data,
|
||||
abilityPoints: getAbilityPoints(
|
||||
parsed.data.headAbilities,
|
||||
parsed.data.clothingAbilities,
|
||||
parsed.data.shoesAbilities
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
res.status(200).end();
|
||||
};
|
||||
|
||||
const buildHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
switch (req.method) {
|
||||
case "POST":
|
||||
await postHandler(req, res);
|
||||
break;
|
||||
case "PUT":
|
||||
await updateHandler(req, res);
|
||||
break;
|
||||
default:
|
||||
return res.status(405).end();
|
||||
}
|
||||
};
|
||||
|
||||
function getAbilityPoints(
|
||||
headAbilities: Ability[],
|
||||
clothingAbilities: Ability[],
|
||||
shoesAbilities: Ability[]
|
||||
) {
|
||||
const result: Partial<Record<Ability, number>> = {};
|
||||
|
||||
const getPointsFromAbilityArray = (ability: Ability, index: number) => {
|
||||
const existingAmount = result[ability] ?? 0;
|
||||
const apsToAdd = index === 0 ? 10 : 3;
|
||||
|
||||
result[ability] = existingAmount + apsToAdd;
|
||||
};
|
||||
|
||||
headAbilities.forEach(getPointsFromAbilityArray);
|
||||
clothingAbilities.forEach(getPointsFromAbilityArray);
|
||||
shoesAbilities.forEach(getPointsFromAbilityArray);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export default buildHandler;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Button, Divider, Select } from "@chakra-ui/react";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import { useLingui } from "@lingui/react";
|
||||
import { RankedMode } from "@prisma/client";
|
||||
import { Build, RankedMode } from "@prisma/client";
|
||||
import BuildCard from "components/builds/BuildCard";
|
||||
import Breadcrumbs from "components/common/Breadcrumbs";
|
||||
import Markdown from "components/common/Markdown";
|
||||
@@ -33,7 +33,7 @@ interface Props {
|
||||
|
||||
const ProfilePage = (props: Props) => {
|
||||
const [showProfileModal, setShowProfileModal] = useState(false);
|
||||
const [showBuildModal, setShowBuildModal] = useState(false);
|
||||
const [buildToEdit, setBuildToEdit] = useState<boolean | Build>(false);
|
||||
|
||||
const [loggedInUser] = useUser();
|
||||
const { data: user } = useSWR<GetUserByIdentifierData>(
|
||||
@@ -64,8 +64,11 @@ const ProfilePage = (props: Props) => {
|
||||
{showProfileModal && (
|
||||
<ProfileModal onClose={() => setShowProfileModal(false)} user={user} />
|
||||
)}
|
||||
{showBuildModal && (
|
||||
<BuildModal onClose={() => setShowBuildModal(false)} />
|
||||
{buildToEdit && (
|
||||
<BuildModal
|
||||
onClose={() => setBuildToEdit(false)}
|
||||
build={typeof buildToEdit === "boolean" ? undefined : buildToEdit}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Breadcrumbs
|
||||
@@ -109,13 +112,19 @@ const ProfilePage = (props: Props) => {
|
||||
</Select>
|
||||
)}
|
||||
{canPostBuilds() && (
|
||||
<Button mt={5} onClick={() => setShowBuildModal(true)}>
|
||||
<Button mt={5} onClick={() => setBuildToEdit(true)}>
|
||||
<Trans>Add build</Trans>
|
||||
</Button>
|
||||
)}
|
||||
<MyInfiniteScroller>
|
||||
{builds.map((build) => (
|
||||
<BuildCard key={build.id} build={build} m={2} showWeapon />
|
||||
<BuildCard
|
||||
key={build.id}
|
||||
build={build}
|
||||
m={2}
|
||||
showWeapon
|
||||
onEdit={(build) => setBuildToEdit(build)}
|
||||
/>
|
||||
))}
|
||||
</MyInfiniteScroller>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user