Skip to content

Commit

Permalink
feat: session dynamic damage
Browse files Browse the repository at this point in the history
  • Loading branch information
rharkor committed Jan 26, 2024
1 parent 7a5c336 commit 08c5be4
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 18 deletions.
2 changes: 2 additions & 0 deletions packages/app/crons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ new CronJob(
async function pingNodes() {
const session = await prisma.session.findFirst()
if (!session || !session.enabled) return
const damagePerHit = session.damagePerHit
const nodes = await prisma.node.findMany()
await Promise.all(
nodes.map(async (node) => {
Expand All @@ -37,6 +38,7 @@ new CronJob(
},
},
status: pingResult.toString(),
damage: damagePerHit ?? 0,
},
})
.catch(() => {})
Expand Down
12 changes: 12 additions & 0 deletions packages/app/prisma/migrations/20240126091548_damage/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
Warnings:
- Added the required column `damage` to the `PingResult` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "PingResult" ADD COLUMN "damage" INTEGER NOT NULL;

-- AlterTable
ALTER TABLE "Session" ADD COLUMN "basePoints" INTEGER,
ADD COLUMN "damagePerHit" INTEGER;
7 changes: 5 additions & 2 deletions packages/app/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,12 @@ model PingResult {
status String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
damage Int
}

model Session {
id String @id @default(cuid())
enabled Boolean @default(false)
id String @id @default(cuid())
enabled Boolean @default(false)
basePoints Int?
damagePerHit Int?
}
4 changes: 3 additions & 1 deletion packages/app/src/api/node/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,15 @@ export const updateNode = async ({ input, ctx: { session } }: apiInputFromSchema
export const updateSession = async ({ input, ctx: { session } }: apiInputFromSchema<typeof updateSessionSchema>) => {
ensureLoggedIn(session)
try {
const { enabled, id } = input
const { enabled, id, basePoints, damagePerHit } = input
await prisma.session.update({
where: {
id,
},
data: {
enabled,
basePoints,
damagePerHit,
},
})
return { success: true }
Expand Down
15 changes: 10 additions & 5 deletions packages/app/src/api/node/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { prisma } from "@/lib/prisma"
import { getNodesResponseSchema } from "@/lib/schemas/nodes"
import { handleApiError } from "@/lib/utils/server-utils"
import { apiInputFromSchema } from "@/types"
import { basePoints, damagePerHit } from "@/types/constants"

export const getNodes = async ({}: apiInputFromSchema<undefined>) => {
try {
Expand All @@ -18,12 +17,18 @@ export const getNodes = async ({}: apiInputFromSchema<undefined>) => {
},
})

const session = await prisma.session.findFirst()
if (!session) throw new Error("Session not found")
const basePoints = session.basePoints

const data: z.infer<ReturnType<typeof getNodesResponseSchema>> = {
nodes: nodes.map((node) => {
const points =
basePoints -
damagePerHit *
node.pingResults.filter((result) => parseInt(result.status) < 200 || parseInt(result.status) >= 300).length
const points = basePoints
? basePoints -
node.pingResults
.filter((result) => parseInt(result.status) < 200 || parseInt(result.status) >= 300)
.reduce((acc, result) => acc + result.damage, 0)
: undefined
return {
id: node.id,
name: node.name,
Expand Down
8 changes: 5 additions & 3 deletions packages/app/src/app/[lang]/(not-protected)/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Button, Input, Spinner } from "@nextui-org/react"

import AddNode from "./add-node"
import Node from "./node"
import UpdateSession from "./update-session"

export default function NodesPageContent({ isLoggedIn }: { isLoggedIn: boolean }) {
const dictionary = useDictionary()
Expand Down Expand Up @@ -44,7 +45,7 @@ export default function NodesPageContent({ isLoggedIn }: { isLoggedIn: boolean }
})[]
| null = nodes.data
? nodes.data.nodes
.sort((a, b) => b.points - a.points)
.sort((a, b) => (b.points ?? 0) - (a.points ?? 0))
.map((node, index) => ({
...node,
rank: index + 1,
Expand All @@ -59,7 +60,7 @@ export default function NodesPageContent({ isLoggedIn }: { isLoggedIn: boolean }
<div className="flex flex-row justify-end gap-2">
<Button
isDisabled={session.isLoading || session.data?.enabled}
onClick={handleDeleteSessionData}
onPress={handleDeleteSessionData}
isLoading={deleteSessionDataMutation.isLoading}
color="danger"
variant="flat"
Expand All @@ -68,12 +69,13 @@ export default function NodesPageContent({ isLoggedIn }: { isLoggedIn: boolean }
</Button>
<Button
isDisabled={session.isLoading}
onClick={handleToggleSession}
onPress={handleToggleSession}
isLoading={updateSessionMutation.isLoading || deleteSessionDataMutation.isLoading}
color={session.data?.enabled ? "danger" : "success"}
>
{session.data?.enabled ? dictionary.disable : dictionary.enable} session
</Button>
<UpdateSession />
<AddNode />
</div>
)}
Expand Down
3 changes: 2 additions & 1 deletion packages/app/src/app/[lang]/(not-protected)/node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function Node({
</CardHeader>
<CardBody className="z-10 flex flex-col gap-2">
<p className="text-foreground text-center text-xl font-medium">
{node.points}
{node.points ?? "---"}
<span className="text-muted-foreground ml-1 text-xs">{dictionary.points}</span>
</p>
<div className="flex flex-row justify-center gap-1">
Expand All @@ -81,6 +81,7 @@ export default function Node({
</>
}
key={index}
isDisabled={status.isSkel}
>
<div
className={cn("h-5 w-2 rounded-full", {
Expand Down
95 changes: 95 additions & 0 deletions packages/app/src/app/[lang]/(not-protected)/update-session.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"use client"

import { useEffect } from "react"
import { useForm } from "react-hook-form"
import { z } from "zod"

import FormField from "@/components/ui/form"
import { ModalHeader } from "@/components/ui/modal"
import { useDictionary } from "@/contexts/dictionary/utils"
import { updateSessionSchema } from "@/lib/schemas/nodes"
import { trpc } from "@/lib/trpc/client"
import { zodResolver } from "@hookform/resolvers/zod"
import { Button, Modal, ModalBody, ModalContent, ModalFooter, useDisclosure } from "@nextui-org/react"

const formSchema = updateSessionSchema

export default function UpdateSession() {
const dictionary = useDictionary()
const utils = trpc.useUtils()
const session = trpc.node.getSession.useQuery(undefined)
const updateSessionMutation = trpc.node.updateSession.useMutation()

const { isOpen, onOpen, onOpenChange, onClose } = useDisclosure()

const form = useForm<z.infer<ReturnType<typeof formSchema>>>({
resolver: zodResolver(formSchema()),
values: {
id: session.data?.id ?? "",
basePoints: session.data?.basePoints ?? 0,
enabled: session.data?.enabled ?? false,
damagePerHit: session.data?.damagePerHit ?? 0,
},
})

const onSubmit = async (data: z.infer<ReturnType<typeof formSchema>>) => {
await updateSessionMutation.mutateAsync(data)
onClose()
utils.node.invalidate()
}

useEffect(() => {
if (!updateSessionMutation.isSuccess) return
form.reset()
}, [updateSessionMutation.isSuccess, form])

return (
<>
<Button
isDisabled={session.isLoading}
onPress={onOpen}
isLoading={updateSessionMutation.isLoading}
color={"warning"}
>
{dictionary.updateSession}
</Button>
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col gap-1">{dictionary.updateSession}</ModalHeader>
<form onSubmit={form.handleSubmit(onSubmit)}>
<ModalBody>
<FormField
name="basePoints"
label={dictionary.basePoints}
placeholder="1000"
form={form}
type="number"
isRequired
/>
<FormField
name="damagePerHit"
form={form}
type="number"
label={dictionary.damagePerHit}
placeholder="10"
isRequired
/>
</ModalBody>
<ModalFooter>
<Button color="default" variant="light" onPress={onClose}>
{dictionary.cancel}
</Button>
<Button color="primary" type="submit" isLoading={updateSessionMutation.isLoading}>
{dictionary.update}
</Button>
</ModalFooter>
</form>
</>
)}
</ModalContent>
</Modal>
</>
)
}
5 changes: 4 additions & 1 deletion packages/app/src/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,8 @@
"enable": "Enable",
"deleteSessionData": "Delete session",
"nodeName": "Node name",
"nodeIp": "Node ip"
"nodeIp": "Node ip",
"updateSession": "Update session",
"basePoints": "Base points",
"damagePerHit": "Damage per hit"
}
5 changes: 4 additions & 1 deletion packages/app/src/langs/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,8 @@
"enable": "Activer",
"deleteSessionData": "Supprimer la session",
"nodeName": "Nom du node",
"nodeIp": "IP du node"
"nodeIp": "IP du node",
"updateSession": "Mettre à jour la session",
"basePoints": "Points de base",
"damagePerHit": "Dégâts par coup"
}
6 changes: 5 additions & 1 deletion packages/app/src/lib/schemas/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const getNodesResponseSchema = () =>
createdAt: z.string(),
})
),
points: z.number(),
points: z.number().optional(),
})
),
})
Expand All @@ -68,11 +68,15 @@ export const getSessionResponseSchema = () =>
z.object({
enabled: z.boolean(),
id: z.string(),
basePoints: z.number().optional().nullable(),
damagePerHit: z.number().optional().nullable(),
})

export const updateSessionSchema = () =>
z.object({
enabled: z.boolean(),
damagePerHit: z.coerce.number().optional(),
basePoints: z.coerce.number().optional(),
id: z.string(),
})

Expand Down
3 changes: 0 additions & 3 deletions packages/app/src/types/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,3 @@ export const emailVerificationExpiration = 1000 * 60 * 60 * 24 * 3 // 3 days
export const resendEmailVerificationExpiration = 1000 * 60 * 2 // 5 minutes
export const defaultMaxPerPage = 100
export const maxUploadSize = 1024 * 1024 * 10 // 10 MB

export const basePoints = 100
export const damagePerHit = 5

0 comments on commit 08c5be4

Please sign in to comment.