Skip to content

Commit

Permalink
Merge pull request #15 from tovyblox/new-changes
Browse files Browse the repository at this point in the history
2.1.1 Beta
  • Loading branch information
WHOOOP authored Dec 22, 2022
2 parents 3a80f4c + b358645 commit 5918779
Show file tree
Hide file tree
Showing 15 changed files with 4,177 additions and 276 deletions.
3,367 changes: 3,367 additions & 0 deletions Tovy2-activity-alpha-old.rbxmx

Large diffs are not rendered by default.

568 changes: 374 additions & 194 deletions Tovy2-activity-alpha.rbxmx

Large diffs are not rendered by default.

278 changes: 234 additions & 44 deletions components/profile/activity.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import React, { useEffect, useState } from "react";
import React, { Fragment, useEffect, useState } from "react";
import { useRecoilState } from "recoil";
import { workspacestate } from "@/state";
import { FC } from '@/types/settingsComponent'
import { Chart, ChartData, ScatterDataPoint } from "chart.js"
import { Line } from "react-chartjs-2";
import type { Quota } from "@prisma/client";
import type { ActivitySession, Quota, inactivityNotice } from "@prisma/client";
import Tooltip from "../tooltip";
import moment from "moment";
import { Dialog, Transition } from "@headlessui/react";
import Button from "../button";
import { IconMessages, IconMoon, IconPlayerPlay, IconWalk } from "@tabler/icons";
import axios from "axios";
import { Toaster, toast } from "react-hot-toast";
import { useRouter } from "next/router";

type Props = {
timeSpent: number;
Expand All @@ -14,16 +21,36 @@ type Props = {
quotas: Quota[];
sessionsHosted: number;
sessionsAttended: number;
avatar: string;
sessions: (ActivitySession & {
user: {
picture: string | null;
};
})[];
notices: inactivityNotice[];
}

const Activity: FC<Props> = ({ timeSpent, timesPlayed, data, quotas, sessionsAttended, sessionsHosted }) => {
const Activity: FC<Props> = ({ timeSpent, timesPlayed, data, quotas, sessionsAttended, sessionsHosted, avatar, sessions, notices }) => {
const router = useRouter();
const { id } = router.query;

const [workspace, setWorkspace] = useRecoilState(workspacestate);
const [loading, setLoading] = useState(true)
const [chartData, setChartData] = useState<ChartData<"line", (number | ScatterDataPoint | null)[], unknown>>({
datasets: []
});
const [chartOptions, setChartOptions] = useState({});
const [timeline, setTimeline] = useState<any>([...sessions, ...notices]);
const [isOpen, setIsOpen] = useState(false);
const [dialogData, setDialogData] = useState<any>({});

useEffect(() => {
setTimeline(timeline.sort((a: any, b: any) => {
const dateA = new Date(a.startTime).getTime();
const dateB = new Date(b.endTime).getTime();
return dateB - dateA;
}));

setChartData({
labels: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
datasets: [
Expand Down Expand Up @@ -81,6 +108,36 @@ const Activity: FC<Props> = ({ timeSpent, timesPlayed, data, quotas, sessionsAtt
}
}

const idleMins = sessions.reduce((acc, session) => { return acc + Number(session.idleTime) }, 0);
const messages = sessions.reduce((acc, session) => { return acc + Number(session.messages) }, 0);

const fetchSession = async (sessionId: string) => {
setLoading(true);
setIsOpen(true);
try {
const { data, status } = await axios.get(`/api/workspace/${id}/activity/${sessionId}`);
if (status !== 200) return toast.error("Could not fetch session.");
if (!data.universe) {
setLoading(false)
return setDialogData({
type: "session",
data: data.message,
universe: null
});

}

setDialogData({
type: "session",
data: data.message,
universe: data.universe
});
setLoading(false)
} catch (error) {
return toast.error("Could not fetch session.");
}
}

const types: {
[key: string]: string

Expand All @@ -91,58 +148,191 @@ const Activity: FC<Props> = ({ timeSpent, timesPlayed, data, quotas, sessionsAtt
}

return (
<div className="mt-2 ">
<div className="grid gap-4 xl:grid-cols-2">
<div>
<div className="bg-white p-4 rounded-md mb-4">
<p className="font-semibold text-2xl">Current week</p>
</div>
<div className="bg-white p-2 rounded-md">
<Line options={chartOptions} data={chartData} />
</div>
</div>
<div className="grid gap-2 grid-cols-1">
<>
<Toaster position="bottom-center" />
<div className="mt-2">
<div className="grid gap-4 xl:grid-cols-2">
<div>
<div className="bg-white p-4 rounded-md mb-4">
<p className="font-semibold text-2xl">Since last timeframe</p>
<p className="font-semibold text-2xl">Current week</p>
</div>
<div className="bg-white p-4 rounded-md">
<p className="font-medium text-xl leading-4 mt-1 text-gray-400">Time spent in-game</p>
<p className="mt-3 text-8xl font-extralight">{timeSpent}m</p>
<div className="bg-white p-2 rounded-md">
<Line options={chartOptions} data={chartData} />
</div>
<div className="bg-white p-4 rounded-md mt-4">
<p className="font-semibold text-2xl">Timeline</p>
{!sessions.length && <p>There is no timeline for this user.</p>}
<ol className={`relative border-l border-gray-200 ml-3 ${sessions.length ? "mt-3" : ""}`}>
{timeline.map((session: any, index: number) => (
<div key={session.id}>
{"reason" in session ? (
<li className="mb-10 ml-6">
<span className="flex absolute -left-3 justify-center items-center w-6 h-6 bg-primary rounded-full ring-4 ring-white">
<img className="rounded-full" src={avatar} alt="timeline avatar" />
</span>
<div className="justify-between items-center p-4 bg-white rounded-lg border border-gray-200 sm:flex">
<time className="mb-1 text-xs font-normal text-gray-400 sm:order-last sm:mb-0">{moment(session.startTime).format("DD MMMM YYYY")} to {moment(session.endTime).format("DD MMMM YYYY")}</time>
<p className="text-lg font-semibold">Inactivity Notice - {session.reason}</p>
</div>
</li>
) : (
<li className="mb-10 ml-6">
<span className="flex absolute -left-3 justify-center items-center w-6 h-6 bg-primary rounded-full ring-4 ring-white">
<img className="rounded-full" src={session.user.picture ? session.user.picture : avatar} alt="timeline avatar" />
</span>
<div className="justify-between items-center p-4 bg-white rounded-lg border border-gray-200 sm:flex cursor-pointer hover:bg-gray-100 transition-colors" onClick={() => fetchSession(session.id)}>
<time className="mb-1 text-xs font-normal text-gray-400 sm:order-last sm:mb-0">{moment(session.startTime).format("HH:mm")} to {moment(session.endTime).format("HH:mm")} on {moment(session.startTime).format("dddd[, ] DD MMMM YYYY")}</time>
<p className="text-lg font-semibold">Activity Session</p>
</div>
</li>
)}
</div>
))}
</ol>
</div>
</div>
<div className="bg-white p-4 rounded-md">
<p className="font-medium text-xl leading-4 mt-1 text-gray-400">Times played</p>
<p className="mt-3 text-8xl font-extralight">{timesPlayed} {timesPlayed == 1 ? 'time' : 'times'}</p>
<div className="grid gap-2 grid-cols-1">
<div>
<div className="bg-white p-4 rounded-md mb-4">
<p className="font-semibold text-2xl">Since last timeframe</p>
</div>
<div className="bg-white p-4 rounded-md">
<p className="font-medium text-xl leading-4 mt-1 text-gray-400">Time spent in-game</p>
<p className="mt-3 text-8xl font-extralight">{timeSpent}m</p>
</div>
<div className="bg-white p-4 rounded-md mt-4">
<p className="font-medium text-xl leading-4 mt-1 text-gray-400">Times played</p>
<p className="mt-3 text-8xl font-extralight">{timesPlayed} {timesPlayed == 1 ? 'time' : 'times'}</p>
</div>
<div className="bg-white p-4 rounded-md mt-4">
<p className="font-medium text-xl leading-4 mt-1 text-gray-400">Messages sent</p>
<p className="mt-3 text-8xl font-extralight">{messages} {messages == 1 ? 'message' : 'msgs'}</p>
</div>
<div className="bg-white p-4 rounded-md mt-4">
<p className="font-medium text-xl leading-4 mt-1 text-gray-400">Idle minutes</p>
<p className="mt-3 text-8xl font-extralight">{idleMins}m</p>
</div>
</div>

</div>

</div>

</div>
<div className="mt-4">
<div className="bg-white p-4 rounded-md mb-4">
<p className="font-semibold text-2xl">Qutoas</p>
<div className="grid gap-3 grid-cols-1 md:grid-cols-2 xl:grid-cols-3 mt-2">
{quotas.map((notice: any) => (
<div className="bg-white p-4 rounded-md ring-1 ring-gray-300" key={notice.id}>
<h2 className="text-lg font-semibold">
{notice.name}
</h2>
<p
className={`font-semibold`}
>
{notice.value} {types[notice.type]} per timeframe
</p>
<Tooltip orientation="top" tooltipText={getQuotaProgress(notice)} isWorkspace>
<div className="w-full rounded-full h-6 mt-2 bg-gray-300 overflow-clip"> <div className="bg-primary h-full" style={{
width: `${getQuotaPercentage(notice)}%`,
}}></div> </div>
</Tooltip>
</div>
))}


<div className="mt-4">
<div className="bg-white p-4 rounded-md mb-4">
<p className="font-semibold text-2xl">Quotas</p>
{!quotas.length && <p>There are no quotas assigned to this user.</p>}
<div className={`grid gap-3 grid-cols-1 md:grid-cols-2 xl:grid-cols-3 ${quotas.length ? "mt-3" : "mt-0"}`}>
{quotas.map((notice: any) => (
<div className="bg-white p-4 rounded-md ring-1 ring-gray-300" key={notice.id}>
<h2 className="text-lg font-semibold">
{notice.name}
</h2>
<p
className={`font-semibold`}
>
{notice.value} {types[notice.type]} per timeframe
</p>
<Tooltip orientation="top" tooltipText={getQuotaProgress(notice)} isWorkspace>
<div className="w-full rounded-full h-6 mt-2 bg-gray-300 overflow-clip"> <div className="bg-primary h-full" style={{
width: `${getQuotaPercentage(notice)}%`,
}}></div> </div>
</Tooltip>
</div>
))}
</div>
</div>
</div>
</div>
</div>

<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={() => setIsOpen(false)}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black bg-opacity-25" />
</Transition.Child>

<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-xl bg-white text-left align-middle shadow-xl transition-all">
{!loading && (
<>
{dialogData.universe && (
<img className="object-cover h-[128px] w-full" draggable="false" src={dialogData?.universe?.thumbnail} alt="thumbnail" />
)}
</>
)}
{loading && (
<div className="h-[128px] w-full bg-gray-200 animate-pulse" />
)}

<div className="p-4">
<div className="bg-white p-2 border rounded-lg border-gray-200 mb-3 text-center shadow-sm">
{!loading && <p className="text-lg font-bold">{dialogData?.universe?.name || 'Unknown Universe'}</p>}
{loading && (
<div className="h-3 my-2 bg-gray-200 mx-auto rounded-full dark:bg-gray-700 max-w-[360px] mb-2.5"></div>
)}
</div>

<div className="flex flex-row space-x-1">
<IconMoon className="my-auto p-0.5" />
{!loading && <p className="my-auto pl-1">Time spent idling - <strong>{Math.round(dialogData.data.idleTime)} minutes</strong></p>}
{loading && (
<div className="my-auto pl-1 h-2 w-64 rounded-full bg-gray-200"></div>
)}
</div>
<div className="flex flex-row space-x-1">
<IconWalk className="my-auto p-0.5" />
{!loading && <p className="my-auto pl-1">Time spent active - <strong>{Math.round(((new Date(dialogData.data.endTime).getTime() - new Date(dialogData.data.startTime).getTime()) - dialogData.data.idleTime) / 60000)} minutes</strong></p>}
{loading && (
<div className="my-auto pl-1 h-2 w-64 rounded-full bg-gray-200"></div>
)}
</div>
<div className="flex flex-row space-x-1">
<IconMessages className="my-auto p-0.5" />
{!loading && <p className="my-auto pl-1">Messages sent - <strong>{dialogData.data.messages ? dialogData.data.messages : "Not tracked"}</strong></p>}
{loading && (
<div className="my-auto pl-1 h-2 w-64 rounded-full bg-gray-200"></div>
)}
</div>
<div className="flex flex-row space-x-1">
<IconPlayerPlay className="my-auto p-0.5" />
{!loading && <p className="my-auto pl-1">Total time spent - <strong>{Math.round((new Date(dialogData.data.endTime).getTime() - new Date(dialogData.data.startTime).getTime()) / 60000)} minutes</strong></p>}
{loading && (
<div className="my-auto pl-1 h-2 w-64 rounded-full bg-gray-200"></div>
)}
</div>

<div className="mt-4 flex">
<Button classoverride="bg-red-500 hover:bg-red-300 ml-0 w-full" onPress={() => setIsOpen(false)}> Close </Button>
</div>
</div>
</Dialog.Panel>

</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
</>
);
};

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tovy",
"version": "2.1.0-beta1",
"version": "2.1.1-beta1",
"private": true,
"scripts": {
"dev": "next dev",
Expand Down
9 changes: 8 additions & 1 deletion pages/api/activity/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ export async function handler(
}
}
})
console.log(config)

if (!config) return res.status(401).json({ success: false, error: "Unauthorized" })
if (!req.body.userid) return res.status(400).json({ success: false, error: "Missing user ID from request body" })
if (typeof req.body.userid !== "number") return res.status(400).json({ success: false, error: "User ID not a number" });
console.log(`${req.body.userid} is creating a session`)
const value = JSON.parse(JSON.stringify(config.value));
if (value.role) {
const userank = await noblox.getRankInGroup(config.workspaceGroupId, req.body.userid);
Expand Down Expand Up @@ -69,6 +72,7 @@ export async function handler(
userId: req.body.userid,
active: true,
startTime: new Date(),
universeId: req.body.placeid ? BigInt(req.body.placeid) : null,
workspaceGroupId: config.workspaceGroupId
}
});
Expand All @@ -88,6 +92,7 @@ export async function handler(
})

if(session.length < 1) return res.status(400).json({ success: false, error: "Session not found" })
console.log(req.body.idleTime)

try {
await prisma.activitySession.update({
Expand All @@ -96,7 +101,9 @@ export async function handler(
},
data: {
endTime: new Date(),
active: false
active: false,
idleTime: req.body.idleTime ? Number(req.body.idleTime) : 0,
messages: req.body.messages ? Number(req.body.messages) : 0,
}
})

Expand Down
Loading

0 comments on commit 5918779

Please sign in to comment.