Skip to content

Commit

Permalink
Merge pull request #109 from scape76/calculate-result-data
Browse files Browse the repository at this point in the history
Calculate result data
  • Loading branch information
webdevcody committed Jul 11, 2023
2 parents c1251d0 + 9f2c0cb commit fca695f
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 20 deletions.
35 changes: 35 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-hover-card": "^1.0.6",
"@radix-ui/react-select": "^1.2.2",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-scroll-area": "^1.0.4",
"@radix-ui/react-select": "^1.2.2",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tooltip": "^1.0.6",
"@t3-oss/env-nextjs": "^0.6.0",
"class-variance-authority": "^0.6.1",
"clsx": "^1.2.1",
Expand Down
10 changes: 5 additions & 5 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ model VerificationToken {
}

model Result {
id String @id @default(cuid())
userId String @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
accuracy Decimal @db.Decimal(5, 2)
wpm Int
id String @id @default(cuid())
userId String @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
accuracy Decimal @db.Decimal(5, 2)
cpm Int
takenTime String @map("taken_time")
errorCount Int? @map("error_count")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
Expand Down
4 changes: 2 additions & 2 deletions src/app/race/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export async function saveUserResult(input: {
userId: User["id"];
timeTaken: string | number;
errors: number;
wpm: number;
cpm: number;
accuracy: number;
}) {

Expand All @@ -16,7 +16,7 @@ export async function saveUserResult(input: {
userId: input.userId,
takenTime: input.timeTaken.toString(),
errorCount: input.errors,
wpm: input.wpm,
cpm: input.cpm,
accuracy: new Prisma.Decimal(input.accuracy),
},
});
Expand Down
37 changes: 26 additions & 11 deletions src/app/race/typingCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@ import RacePositionTracker from "./racePositionTracker";

const code = `printf("hello world")`;

function calculateWPM() {
return 1;
function calculateCPM(
numberOfCharacters: number,
secondsTaken: number
): number {
const minutesTaken = secondsTaken / 60;
return Math.round(numberOfCharacters / minutesTaken);
}

function calculateAccuracy() {
return 0.92;
function calculateAccuracy(
numberOfCharacters: number,
errorsCount: number
): number {
return (1 - (errorsCount / numberOfCharacters))
}

interface TypingCodeProps {
Expand All @@ -43,12 +50,12 @@ export default function TypingCode({ user }: TypingCodeProps) {
userId: user.id,
timeTaken,
errors: errors.length,
wpm: calculateWPM(),
accuracy: calculateAccuracy(),
cpm: calculateCPM(code.length, timeTaken),
accuracy: calculateAccuracy(code.length, errors.length),
});
console.log("Time taken:", timeTaken);
}
if (inputEl.current !== null){
if (inputEl.current !== null) {
inputEl.current.focus();
}

Expand All @@ -62,7 +69,10 @@ export default function TypingCode({ user }: TypingCodeProps) {
if (!isTyping && event.target.value.length > 0) {
setStartTime(new Date());
setIsTyping(true);
} else if (event.target.value === code) {
} else if (
event.target.value === code ||
event.target.value.length === code.length
) {
setEndTime(new Date());
setIsTyping(false);
setIsEnd(true)
Expand All @@ -75,15 +85,16 @@ export default function TypingCode({ user }: TypingCodeProps) {
const newErrors: number[] = Array.from(event.target.value)
.map((char, index) => (char !== currentText[index] ? index : -1))
.filter((index) => index !== -1);
console.log(newErrors);
return newErrors;
});
}
};
const focusOnCode = () => {
if (inputEl.current !== null){
if (inputEl.current !== null) {
inputEl.current.focus();
}
}
};
const handleRestart = () => {
setInput("");
setIsTyping(false);
Expand All @@ -94,7 +105,11 @@ export default function TypingCode({ user }: TypingCodeProps) {

return (
<div className="w-3/4 p-8 bg-accent rounded-md">
<RacePositionTracker inputLength={input.length - errors.length} actualSnippetLength={code.length} user={user}/>
<RacePositionTracker
inputLength={input.length - errors.length}
actualSnippetLength={code.length}
user={user}
/>
<h1 className="text-2xl font-bold mb-4">Type this code:</h1>
{/* eslint-disable-next-line */}
<code onClick={focusOnCode}>
Expand Down
2 changes: 2 additions & 0 deletions src/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
RefreshCcwIcon,
Settings,
User2,
Info,
type Icon as LucideIcon,
} from "lucide-react";

Expand Down Expand Up @@ -49,4 +50,5 @@ export const Icons = {
mobileNavClosed: ChevronLeftSquareIcon,
refresh: RefreshCcwIcon,
picture: ImageIcon,
info: Info
};
49 changes: 49 additions & 0 deletions src/components/results-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ import { type ColumnDef } from "unstyled-table";
import Image from "next/image";
import Link from "next/link";
import { DataTable } from "./data-table";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Icons } from "./icons";

type ResultWithUser = Result & { user: User };

Expand Down Expand Up @@ -50,6 +57,48 @@ export function ResultsTable({ data, pageCount }: ResultsTableProps) {
accessorKey: "takenTime",
header: "Taken time",
},
{
// get the data.takenTime value
accessorKey: "cpm",
header: () => {
return (
<div className="flex items-center gap-2">
<span>Cpm</span>
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<Icons.info className="w-4 h-4" />
</TooltipTrigger>
<TooltipContent>
<p>Characters per minute</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
);
},
},
{
// get the data.takenTime value
accessorKey: "accuracy",
header: "Accuracy",
cell: ({ cell }) => {
const accuracy = cell.getValue() as number;

if (accuracy > 0.8) {
return <span className="text-green-600">{accuracy}</span>;
} else if (accuracy > 0.5) {
return <span className="text-orange-600">{accuracy}</span>;
} else {
return <span className="text-destructive">{accuracy}</span>;
}
},
},
{
// get the data.takenTime value
accessorKey: "errorCount",
header: "Errors",
},
],
[]
);
Expand Down
30 changes: 30 additions & 0 deletions src/components/ui/tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"use client"

import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"

import { cn } from "@/lib/utils"

const TooltipProvider = TooltipPrimitive.Provider

const Tooltip = TooltipPrimitive.Root

const TooltipTrigger = TooltipPrimitive.Trigger

const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName

export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }

0 comments on commit fca695f

Please sign in to comment.