Skip to content

Commit

Permalink
Functional app
Browse files Browse the repository at this point in the history
  • Loading branch information
Rohithgilla12 committed Aug 29, 2022
1 parent f44ba87 commit ac95031
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 82 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@trpc/next": "^9.27.2",
"@trpc/react": "^9.27.2",
"@trpc/server": "^9.27.2",
"copy-to-clipboard": "^3.3.2",
"daisyui": "^2.24.0",
"nanoid": "^4.0.0",
"next": "12.2.5",
Expand Down
40 changes: 40 additions & 0 deletions src/layouts/BaseLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { Suspense } from "react";
import { signIn, signOut, useSession } from "next-auth/react";

import Head from "next/head";

interface BaseLayoutProps {
title: string;
children?: React.ReactNode;
}

export const BaseLayout: React.FC<BaseLayoutProps> = ({ children, title }) => {
const { status, data } = useSession();

return (
<Suspense>
<Head>
<title>{`Shortcut | ${title}`} </title>
<meta name="description" content="Short Cut | Fastest URL Shortner" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div className="navbar bg-base-100">
<div className="flex-1">
<a className="btn btn-ghost normal-case text-xl">Short Cut</a>
</div>
<div className="flex-none gap-2">
{status === "unauthenticated" ? (
<button className="btn btn-primary" onClick={() => signIn()}>
Sign in
</button>
) : (
<button className="btn btn-primary" onClick={() => signOut()}>
Sign out
</button>
)}
</div>
</div>
{children}
</Suspense>
);
};
1 change: 1 addition & 0 deletions src/mocks/mockData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export const mockData = [
{ date: "Sat Aug 27 2022", clicks: 3 },
{ date: "Sun Aug 28 2022", clicks: 3 },
{ date: "Fri Aug 26 2022", clicks: 1 },
{ date: "Fri Aug 27 2022", clicks: 4 },
];
80 changes: 31 additions & 49 deletions src/pages/analytics/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,15 @@
import { useEffect, useState } from "react";
import { ChartProvider, LineSeries, Tooltip, XAxis, YAxis } from "rough-charts";

import { Analytics } from "@prisma/client";
import { NextPage } from "next";
import { useRouter } from "next/router";
import { ChartProvider, LineSeries, Tooltip, XAxis, YAxis } from "rough-charts";
import { trpc } from "../../utils/trpc";

interface DateClicks {
date: string;
clicks: number;
}

type AssetMapData = {
[key: string]: Analytics[];
};
import { useRouter } from "next/router";

const Analytics: NextPage = () => {
const router = useRouter();
const { id } = router.query;

const [dateClicksData, setDateClicksData] = useState<DateClicks[]>([]);

const urlAnalytics = trpc.useQuery([
"analyticsgetLinkAnalytics",
"analyticsgetGraphData",
{ id: parseInt(id as string) },
]);

Expand All @@ -31,28 +18,6 @@ const Analytics: NextPage = () => {
{ id: parseInt(id as string) },
]);

useEffect(() => {
if (urlAnalytics.data) {
const assetMapData: AssetMapData = {};
urlAnalytics.data.forEach((data) => {
const date = new Date(data.createdAt);
const dateString = date.toDateString();

if (assetMapData[dateString] === undefined) {
assetMapData[dateString] = [data];
} else {
assetMapData[dateString]?.push(data);
}
});
const dateChartData: DateClicks[] = [];
Object.keys(assetMapData).forEach((key) => {
dateChartData.push({ date: key, clicks: assetMapData[key].length });
});

setDateClicksData(dateChartData);
}
}, [urlAnalytics.data]);

//Future Scope: Check if the user is authenticated and if the user is the owner of the short link

return (
Expand All @@ -65,29 +30,46 @@ const Analytics: NextPage = () => {
<h3 className="text-xl">Slug: {shortLink.data.slug}</h3>
</div>
)}
{dateClicksData && (
{urlAnalytics.data && (
<div className="stats shadow">
<div className="stat">
<div className="stat-title">Total Page Views</div>
{/* Count all clicks in dataClicksData*/}
<div className="stat-value">
{dateClicksData.reduce((a, b) => a + b.clicks, 0)}
{urlAnalytics.data.dateChartData.reduce(
(a, b) => a + b.clicks,
0
)}
</div>
</div>
</div>
)}

<div className="m-4 flex flex-col">
<div className="my-4 w-screen">
<ChartProvider data={dateClicksData} height={300}>
<XAxis dataKey="date" />
<LineSeries dataKey="clicks" />
{/* <BarSeries dataKey="clicks" /> */}
<YAxis dataKey="clicks" format={(count) => `${count}`} />
<Tooltip>
{({ date, clicks }) => `Views on ${date}: ${clicks}`}
</Tooltip>
</ChartProvider>
{urlAnalytics.data && (
<ChartProvider data={urlAnalytics.data.dateChartData} height={300}>
<XAxis dataKey="date" />
<LineSeries dataKey="clicks" />
{/* <BarSeries dataKey="clicks" /> */}
<YAxis dataKey="clicks" format={(count) => `${count}`} />
<Tooltip>
{({ date, clicks }) => `Views on ${date}: ${clicks}`}
</Tooltip>
</ChartProvider>
)}
</div>
</div>
<div className="card bg-bg-primary w-full text-neutral-content">
<div className="card-body items-center">
<h2 className="card-title">Future Scope</h2>
<ul>
<li>
Time analysis, know when your users are most actively visting the
link
</li>
<li>Export data into your favorite type</li>
</ul>
</div>
</div>
</div>
Expand Down
52 changes: 19 additions & 33 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { signIn, signOut, useSession } from "next-auth/react";

import Head from "next/head";
import { BaseLayout } from "../layouts/BaseLayout";
import Link from "next/link";
import type { NextPage } from "next";
import { Suspense } from "react";
import copy from "copy-to-clipboard";
import dynamic from "next/dynamic";
import { trpc } from "../utils/trpc";

Expand All @@ -15,34 +13,11 @@ const CreateShortCutForm = dynamic(
);

const Home: NextPage = () => {
const { status, data } = useSession();

const userLinks = trpc.useQuery(["shortCut.getAllShortLinksByUser"]);

return (
<>
<Head>
<title>Shortcut | Home</title>
<meta name="description" content="Short Cut | Fastest URL Shortner" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Suspense>
<div className="navbar bg-base-100">
<div className="flex-1">
<a className="btn btn-ghost normal-case text-xl">Short Cut</a>
</div>
<div className="flex-none gap-2">
{status === "unauthenticated" ? (
<button className="btn btn-primary" onClick={() => signIn()}>
Sign in
</button>
) : (
<button className="btn btn-primary" onClick={() => signOut()}>
Sign out
</button>
)}
</div>
</div>
<BaseLayout title={"Home"}>
<>
<main className="container mx-auto flex flex-col items-center justify-center min-h-screen p-4">
<CreateShortCutForm />
<div className="overflow-x-auto">
Expand All @@ -53,6 +28,7 @@ const Home: NextPage = () => {
<th>URL</th>
<th>Slug</th>
<th>Analytics</th>
<th>Copy</th>
</tr>
</thead>
<tbody>
Expand All @@ -73,17 +49,27 @@ const Home: NextPage = () => {
<span className="link">Analytics</span>
</Link>
</td>
<td>
<button
onClick={() =>
copy(
`https://short-cut-redis.vercel.app/r/${link.slug}`
)
}
className="btn btn-square btn-outline"
>
Copy
</button>
</td>
</tr>
))
)}
</tbody>
</table>
</div>

{JSON.stringify(userLinks.data)}
</main>
</Suspense>
</>
</>
</BaseLayout>
);
};

Expand Down
43 changes: 43 additions & 0 deletions src/server/router/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { Analytics } from "@prisma/client";
import { createRouter } from "./context";
import { getShortLink } from "./../../utils/redis";
import { z } from "zod";

interface DateClicks {
date: string;
clicks: number;
}

type AssetMapData = {
[key: string]: Analytics[];
};

export const analyticsRouter = createRouter()
.mutation("createAnalytics", {
input: z.object({
Expand Down Expand Up @@ -32,4 +42,37 @@ export const analyticsRouter = createRouter()
},
});
},
})
.query("getGraphData", {
input: z.object({
id: z.number(),
}),
async resolve({ input, ctx }) {
const analytics = await ctx.prisma.analytics.findMany({
where: {
shortLinkId: input.id,
},
});
const assetMapData: AssetMapData = {};
analytics.forEach((data) => {
const date = new Date(data.createdAt);
const dateString = date.toDateString();
if (assetMapData[dateString] === undefined) {
assetMapData[dateString] = [data];
} else {
assetMapData[dateString]?.push(data);
}
});
const dateChartData: DateClicks[] = [];
Object.keys(assetMapData).forEach((key) => {
dateChartData.push({
date: key,
clicks: assetMapData[key]?.length ?? 0,
});
});

return {
dateChartData,
};
},
});
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,13 @@ copy-anything@^3.0.2:
dependencies:
is-what "^4.1.6"

copy-to-clipboard@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz#5b263ec2366224b100181dded7ce0579b340c107"
integrity sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==
dependencies:
toggle-selection "^1.0.6"

core-js-pure@^3.20.2:
version "3.25.0"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.25.0.tgz#f8d1f176ff29abbfeb610110de891d5ae5a361d4"
Expand Down Expand Up @@ -2599,6 +2606,11 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"

toggle-selection@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==

tsconfig-paths@^3.14.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
Expand Down

0 comments on commit ac95031

Please sign in to comment.