Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/analytics #1

Merged
merged 1 commit into from
Aug 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}
2 changes: 2 additions & 0 deletions backend/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { ObjectId } from "mongodb"
type User = {
id: ObjectId;
name: string;
bio?: string;
email: string;
password: string;
avatar: string;
createdAt?: Date;
location?: string;
isAdmin?: boolean;
}

export default User
3 changes: 2 additions & 1 deletion backend/utils/secrets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ if (!fs.existsSync('.env')) {
}

export const ENVIRONMENT = process.env.NODE_ENV
export const IS_PROD = ENVIRONMENT === 'production'
// export const IS_PROD = ENVIRONMENT === 'production'
export const IS_PROD = true

export const MONGO_URI = IS_PROD ? process.env.MONGO_URI : process.env.MONGO_URI_LOCAL
36 changes: 36 additions & 0 deletions components/Admin/Analytics/Analytics.Styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import styled from 'styled-components'

export const StyledAnalytics = styled.div`
.analytics-group {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 20px;

.analytics-group-item {
border-radius: 6px;
width: 100%;
background-color: rgb(255, 255, 255, 0.075);

.analytics-heading {
padding: 12px 20px;
border-bottom: 1px solid rgb(255, 255, 255, 0.075);

.analytics-heading-title {
font-size: 13px;
font-weight: 600;
letter-spacing: 0.05rem;
color: rgb(255, 255, 255, 0.45);
}
}

.analytics-data {
padding: 20px;

.analytics-amount {
font-size: 32px;
font-weight: 400;
}
}
}
}
`
2 changes: 2 additions & 0 deletions components/Auth/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ const Login: FC = () => {
updateUser({
id: resData._id,
name: resData.name,
bio: resData.bio,
email: resData.email,
avatar: resData.avatar,
isAdmin: resData.isAdmin
})
)

Expand Down
6 changes: 4 additions & 2 deletions components/Auth/Register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,11 @@ const Register: FC = () => {
if (res.success) {
dispatch(updateUser({
id: resData._id,
name: resData.name,
name: resData.name,
bio: resData.bio,
email: resData.email,
avatar: resData.avatar
avatar: resData.avatar,
isAdmin: resData.isAdmin
}))

router.push('/')
Expand Down
24 changes: 22 additions & 2 deletions components/Layout/Sidebar/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { HomeIcon, MapIcon, UsersIcon, HeartIcon, DesktopComputerIcon } from '@heroicons/react/outline'
import Link from 'next/link'
import React, { FC } from 'react'
import { useSelector } from 'react-redux'
import { StyledSidebar } from '.'
import { selectUser } from '../../../../redux/user'
import { Item } from './Item'

const Sidebar: FC = () => {
const user = useSelector(selectUser)

return (
<StyledSidebar>
<div className="sidebarItemGrid">
Expand Down Expand Up @@ -73,7 +77,7 @@ const Sidebar: FC = () => {
</div>
</div>

<div className="quickLinksSection">
{/* <div className="quickLinksSection">
<div className="title">
<span>Learn</span>
</div>
Expand All @@ -99,7 +103,23 @@ const Sidebar: FC = () => {
<span>Languages</span>
</div>
</div>
</div>
</div> */}

{user.isAdmin && (
<div className="quickLinksSection">
<div className="title">
<span>Admin</span>
</div>

<div className="quickLinkItemWrapper">
<Link href="/admin/analytics">
<a className="linkItem">
<span>Analytics</span>
</a>
</Link>
</div>
</div>
)}
</StyledSidebar>
)
}
Expand Down
5 changes: 4 additions & 1 deletion components/System/Avatar/Avatar.Styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ const StyledAvatar = styled.div<StyledProps>`
height: ${({ size }) => size ? size : '32'}px;
width: ${({ size }) => size ? size : '32'}px;
cursor: pointer;
background-color: #131315;
border-radius: 50%;
position: relative;

@media (max-width: 600px) {
height: ${({ mobileSize }) => mobileSize && mobileSize}px;
width: ${({ mobileSize }) => mobileSize && mobileSize}px;
}

img {
border: ${({ outline, customOutline }) => outline ? '1px solid rgba(255, 255, 255, 0.10)' :
box-shadow: ${({ outline, customOutline }) => outline ? 'inset 0 0 0 1px rgba(255, 255, 255, 0.10)' :
(customOutline ? customOutline : 'none')}!important;
border-radius: 50%!important;
}
Expand Down
88 changes: 88 additions & 0 deletions pages/admin/analytics/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import type { NextPage } from 'next'
import styled from 'styled-components'
import React, { useEffect, useState } from 'react'
import { Layout } from '../../../components/Layout'
import { StyledAnalytics } from '../../../components/Admin/Analytics/Analytics.Styled'
import { mailman } from '../../../backend/utils/mailman'

const StyledHeader = styled.h1`
font-size: 1.75rem;
font-weight: 700;
color: #fff;
`

type AnalyticsType = {
users: number,
spGames: number,
challenges: number,
aerialGames: number,
}

const AnalyticsPage: NextPage = () => {
const [loading, setLoading] = useState(true)
const [analytics, setAnalytics] = useState<AnalyticsType>()

const loadAnalytics = async () => {
setLoading(true)

const { status, res: { data } } = await mailman('analytics', 'GET')

setAnalytics(data)

setLoading(false)
}

useEffect(() => {
loadAnalytics()
}, [])

return (
<Layout>
<StyledHeader>Analytics</StyledHeader>

<StyledAnalytics>
{loading && (
<span>Loading...</span>
)}
{!loading && (
<div className="analytics-group">
<div className="analytics-group-item">
<div className="analytics-heading">
<span className="analytics-heading-title">USERS</span>
</div>
<div className="analytics-data">
<span className="analytics-amount">{analytics?.users}</span>
</div>
</div>
<div className="analytics-group-item">
<div className="analytics-heading">
<span className="analytics-heading-title">SINGLE PLAYER GAMES</span>
</div>
<div className="analytics-data">
<span className="analytics-amount">{analytics?.spGames}</span>
</div>
</div>
<div className="analytics-group-item">
<div className="analytics-heading">
<span className="analytics-heading-title">CHALLENGES</span>
</div>
<div className="analytics-data">
<span className="analytics-amount">{analytics?.challenges}</span>
</div>
</div>
<div className="analytics-group-item">
<div className="analytics-heading">
<span className="analytics-heading-title">AERIAL GAMES</span>
</div>
<div className="analytics-data">
<span className="analytics-amount">{analytics?.aerialGames}</span>
</div>
</div>
</div>
)}
</StyledAnalytics>
</Layout>
)
}

export default AnalyticsPage
34 changes: 34 additions & 0 deletions pages/api/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { collections, dbConnect } from '../../../backend/utils/dbConnect'
import { NextApiRequest, NextApiResponse } from 'next'

export default async (req: NextApiRequest, res: NextApiResponse) => {
try {
await dbConnect()

if (req.method === 'GET') {
const userCount = await collections.users?.estimatedDocumentCount()
const spGamesCount = await collections.games?.estimatedDocumentCount()
const challengesCount = await collections.challenges?.estimatedDocumentCount()
const aerialCount = await collections.aerialGames?.estimatedDocumentCount()



res.status(200).json({
success: true,
data: {
users: userCount,
spGames: spGamesCount,
challenges: challengesCount,
aerialGames: aerialCount,
recentUsers: recentUsers
}
})
}
else {
res.status(500).json({ message: 'Invalid request' })
}
}
catch (err) {
res.status(500).json({ message: 'Something went wrong, please try again later' })
}
}
25 changes: 25 additions & 0 deletions pages/api/users/count.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { collections, dbConnect } from '../../../backend/utils/dbConnect'
import { NextApiRequest, NextApiResponse } from 'next'

export default async (req: NextApiRequest, res: NextApiResponse) => {
try {
await dbConnect()

if (req.method === 'GET') {
const count = await collections.users?.estimatedDocumentCount()

res.status(200).json({
success: true,
data: {
count
}
})
}
else {
res.status(500).json({ message: 'Invalid request' })
}
}
catch (err) {
res.status(500).json({ message: 'Something went wrong, please try again later' })
}
}
Loading