From 5fb290367ced603ed987733880b31217fbb47b6b Mon Sep 17 00:00:00 2001 From: Vijesh Shetty Date: Tue, 14 Jan 2025 16:24:02 +0530 Subject: [PATCH] some fixes --- .env.example | 7 -- app/app/(dashboard)/links/[id]/page.tsx | 29 +---- components/CardComponents/LinkCard.tsx | 112 +++++++++++++----- interfaces/types.ts | 5 +- lib/actions/getAnalyticsAction.ts | 5 +- lib/actions/getLinksAction.ts | 69 +++++++++-- .../20250114095945_reln/migration.sql | 11 ++ prisma/migrations/migration_lock.toml | 2 +- prisma/schema.prisma | 5 +- 9 files changed, 172 insertions(+), 73 deletions(-) delete mode 100644 .env.example create mode 100644 prisma/migrations/20250114095945_reln/migration.sql diff --git a/.env.example b/.env.example deleted file mode 100644 index 8be556e..0000000 --- a/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -PG_DATABASE_URL="postgresql://user:password@host:5432/database" -CH_DATABASE_URL="clickhouse://user:password@host:8123/database" -REDIS_URL="redis://localhost:6379/0" -NEXTAUTH_SECRET="test_secret" -GOOGLE_CLIENT_ID="test-app-google.apps.googleusercontent.com" -GOOGLE_CLIENT_SECRET="test-secret" -REDIRECT_URL="https://eurl.dev" diff --git a/app/app/(dashboard)/links/[id]/page.tsx b/app/app/(dashboard)/links/[id]/page.tsx index f736ea7..341266d 100644 --- a/app/app/(dashboard)/links/[id]/page.tsx +++ b/app/app/(dashboard)/links/[id]/page.tsx @@ -108,34 +108,17 @@ export default function Page({ long_url: "https://example.com/e7b9f3a7-0a15-4b7d-8d62-0d5f1a52e73e", created_at: new Date("2023-05-28T12:34:56Z"), title: "Sample Title", + _count: { + click_analytics: 100 + } }); const router = useRouter(); useEffect(() => { setLoading(true); getLinkDetails(decodeId(params.id).toString()).then((res) => { - if (res.status == HTTP_STATUS.NOT_FOUND) { - toast.error("Link not found"); - router.push("/app/links"); - return; - } - - if (res.link) { - //@ts-ignore - setfetchLink(res.link); - //@ts-ignore - setTitle(res.link.title); - //@ts-ignore - setShortcode(res.link.short_code); - } - //@ts-ignore - // getAnalyticsAction(res.link.short_code).then((e) => { - // //@ts-ignore - // // setLink(e); - // setNoDataSet(Object.keys(e.devices).length); - // setLoading(false); - // }); - setLoading(false); + setfetchLink(res.link) + setLoading(false) }); }, [router, params.id]); @@ -261,7 +244,7 @@ export default function Page({

Engagements

-

{link.engagement}

+

{fetchLink._count.click_analytics}

Last 7 days

diff --git a/components/CardComponents/LinkCard.tsx b/components/CardComponents/LinkCard.tsx index 1e7abb4..903f2e1 100644 --- a/components/CardComponents/LinkCard.tsx +++ b/components/CardComponents/LinkCard.tsx @@ -1,5 +1,6 @@ "use client"; import { + BarChart2, Calendar, Copy, LinkIcon, @@ -14,21 +15,32 @@ import { linkType } from "@/interfaces/types"; import { useState } from "react"; import { useRouter } from "next/navigation"; import encodeId from "@/lib/services/encodeId"; +import { + HoverCard, + HoverCardContent, + HoverCardTrigger, +} from "@radix-ui/react-hover-card"; const months = [ - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", ]; -export function LinkCard({ - link, -}: { - link: linkType; -}) { - const REDIRECT_URL:string = process.env.REDIRECT_URL || "https://eurl.dev"; - const [shortCode,setShortcode] = useState(link.short_code); - const shortLink:string = `${REDIRECT_URL}/${shortCode}` - const [title,setTitle] = useState(link.title) +export function LinkCard({ link }: { link: linkType }) { + const REDIRECT_URL: string = process.env.REDIRECT_URL || "https://eurl.dev"; + const [shortCode, setShortcode] = useState(link.short_code); + const shortLink: string = `${REDIRECT_URL}/${shortCode}`; + const [title, setTitle] = useState(link.title); const router = useRouter(); return ( @@ -39,11 +51,19 @@ export function LinkCard({
-

router.push(`/app/links/${encodeId(link.id)}`)} className="text-lg lg:w-[53%] w-full break-all font-bold hover:underline cursor-pointer"> +

router.push(`/app/links/${encodeId(link.id)}`)} + className="text-lg lg:w-[53%] w-full break-all font-bold hover:underline cursor-pointer" + > {title}

- @@ -53,7 +73,11 @@ export function LinkCard({ Share - +
-

{ - window.open( - shortLink, - "_blank" - ) - }} className="text-blue-400 mt-1 hover:underline cursor-pointer w-fit"> +

{ + window.open(shortLink, "_blank"); + }} + className="text-blue-400 mt-1 hover:underline cursor-pointer w-fit" + > {shortLink}

-

{ - window.open( - link.long_url, - "_blank" - ) - }} className="mt-2 text-sm hover:underline cursor-pointer"> - {link.long_url.length >= 10?<>{link.long_url.slice(0,30)}.....:<>{link.long_url}} +

{ + window.open(link.long_url, "_blank"); + }} + className="mt-2 text-sm hover:underline cursor-pointer" + > + {link.long_url.length >= 10 ? ( + <>{link.long_url.slice(0, 30)}..... + ) : ( + <>{link.long_url} + )}

+
+ +

+ {link._count.click_analytics}{" "} + + + + Includes short link clicks, QR Code scans + + +

+
-

{months[link.created_at.getMonth()]} {link.created_at.getDate()},{link.created_at.getFullYear()}

+

+ {months[link.created_at.getMonth()]} {link.created_at.getDate()} + ,{link.created_at.getFullYear()} +

- @@ -96,7 +144,11 @@ export function LinkCard({ - + diff --git a/interfaces/types.ts b/interfaces/types.ts index c1f50a2..d0a3816 100644 --- a/interfaces/types.ts +++ b/interfaces/types.ts @@ -65,6 +65,8 @@ export type publicLinkType = { clicks? : string } +type countType = Record + export type linkType = { id:number, user_id: number; @@ -72,7 +74,8 @@ export type linkType = { long_url: string; created_at: Date; title: string | null; - engagements?: number + engagements?: number; + _count:countType } export type paginationType = { diff --git a/lib/actions/getAnalyticsAction.ts b/lib/actions/getAnalyticsAction.ts index e5c3b0e..be9b2ea 100644 --- a/lib/actions/getAnalyticsAction.ts +++ b/lib/actions/getAnalyticsAction.ts @@ -1,3 +1,6 @@ "use server"; -export async function getAnalyticsAction(shortcode: string) {} +export async function getAnalyticsAction(shortcode: string) { + +} + diff --git a/lib/actions/getLinksAction.ts b/lib/actions/getLinksAction.ts index e307682..18c76de 100644 --- a/lib/actions/getLinksAction.ts +++ b/lib/actions/getLinksAction.ts @@ -5,11 +5,9 @@ import { ISessionType } from "@/interfaces/url"; import authOptions from "@/lib/authOptions"; import PrismaClientManager from "@/lib/services/pgConnect"; import { HTTP_STATUS } from "@/lib/constants"; -import { getEngagements } from "../services/getEngagements"; +const prisma = PrismaClientManager.getInstance().getPrismaClient(); export async function getLinks(pageNumber: string) { - const posgresInstance = PrismaClientManager.getInstance(); - const prisma = posgresInstance.getPrismaClient(); const session: ISessionType | null = await getServerSession(authOptions); // const searchParams = req.nextUrl.searchParams; @@ -48,12 +46,17 @@ export async function getLinks(pageNumber: string) { }, skip: (parseInt(page) - 1) * parseInt(page_size), take: parseInt(page_size), + include: { + _count : { + select: { + click_analytics: true + } + } + } }); - const engaged_links = await getEngagements(links); - return { - links:engaged_links, + links, totalLinks, total_pages, status: HTTP_STATUS.CREATED @@ -68,7 +71,6 @@ export async function getLinks(pageNumber: string) { export async function getLinkDetails(linkId:string){ const session: ISessionType | null = await getServerSession(authOptions); - const prisma = PrismaClientManager.getInstance().getPrismaClient(); if (!session?.user) { return { @@ -94,6 +96,13 @@ export async function getLinkDetails(linkId:string){ where:{ id : Number.parseInt(linkId), user_id : parseInt(session.user.sub) + }, + include: { + _count: { + select: { + click_analytics: true + } + } } }) @@ -105,4 +114,48 @@ export async function getLinkDetails(linkId:string){ } return {status:HTTP_STATUS.OK,link}; -} \ No newline at end of file +} + +export const lastSevenDaysAnalytics = async (code: string) => { + const todayDate = new Date(); + const sevenDaysAgo = new Date(todayDate); + sevenDaysAgo.setDate(todayDate.getDate() - 7); + + const lastWeekStartDate = new Date(sevenDaysAgo); + lastWeekStartDate.setDate(lastWeekStartDate.getDate() - 7); + const lastWeekEndDate = new Date(sevenDaysAgo); + + const [thisWeekCount, lastWeekCount] = await Promise.all([ + prisma.clickAnalytics.count({ + where: { + code, + timestamp: { + gte: sevenDaysAgo, + lte: todayDate, + }, + }, + }), + prisma.clickAnalytics.count({ + where: { + code, + timestamp: { + gte: lastWeekStartDate, + lte: lastWeekEndDate, + }, + }, + }), + ]); + + const percentageChange = + lastWeekCount !== 0 + ? ((thisWeekCount - lastWeekCount) / lastWeekCount) * 100 + : thisWeekCount !== 0 + ? 100 + : 0; + + return { + totalVisitsThisWeek: thisWeekCount, + totalVisitsLastWeek: lastWeekCount, + percentageChange, + }; +}; \ No newline at end of file diff --git a/prisma/migrations/20250114095945_reln/migration.sql b/prisma/migrations/20250114095945_reln/migration.sql new file mode 100644 index 0000000..e5d764c --- /dev/null +++ b/prisma/migrations/20250114095945_reln/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - Made the column `code` on table `ClickAnalytics` required. This step will fail if there are existing NULL values in that column. + +*/ +-- AlterTable +ALTER TABLE "ClickAnalytics" ALTER COLUMN "code" SET NOT NULL; + +-- AddForeignKey +ALTER TABLE "ClickAnalytics" ADD CONSTRAINT "ClickAnalytics_code_fkey" FOREIGN KEY ("code") REFERENCES "links"("short_code") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml index 648c57f..fbffa92 100644 --- a/prisma/migrations/migration_lock.toml +++ b/prisma/migrations/migration_lock.toml @@ -1,3 +1,3 @@ # Please do not edit this file manually -# It should be added in your version-control system (e.g., Git) +# It should be added in your version-control system (i.e. Git) provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index fa66950..8b1b871 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -25,13 +25,13 @@ model links { long_url String created_at DateTime title String? + click_analytics ClickAnalytics[] @@index(short_code) } model ClickAnalytics { id Int @id @default(autoincrement()) - code String? browser String? os String? device String? @@ -39,7 +39,8 @@ model ClickAnalytics { region String? city String? timestamp DateTime @default(now()) @db.Date - + link links @relation(fields: [code], references: [short_code]) + code String @@index([code, timestamp]) @@index(code) }