diff --git a/functions/schema.sql b/functions/schema.sql index b616c22..8654c23 100644 --- a/functions/schema.sql +++ b/functions/schema.sql @@ -1,7 +1,14 @@ -DROP TABLE IF EXISTS Visits; -CREATE TABLE IF NOT EXISTS Visits ( - slug TEXT PRIMARY KEY, +-- DROP TABLE IF EXISTS Visits; +-- CREATE TABLE IF NOT EXISTS Visits ( +-- slug TEXT PRIMARY KEY, +-- count INTEGER NOT NULL DEFAULT 0, +-- created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +-- ); +-- INSERT INTO Visits (slug, count) VALUES ('/', 0); + +CREATE TABLE IF NOT EXISTS Events ( + event_name TEXT PRIMARY KEY, count INTEGER NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); -INSERT INTO Visits (slug, count) VALUES ('/', 0); +INSERT INTO Events (event_name, count) VALUES ('/', 0); diff --git a/functions/src/index.ts b/functions/src/index.ts index 4b2af65..c1e004e 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -69,6 +69,73 @@ router.get("/api/get-article-hits", async ({query, method, headers}: CustomReque } }); +router.get( + "/api/add-event", + async ({query, method, headers}: CustomRequest, env) => { + + // CREATE TABLE IF NOT EXISTS Events ( + // event_name TEXT PRIMARY KEY, + // count INTEGER NOT NULL DEFAULT 0, + // params TEXT, + // created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP + // ); + + // handle CORS preflight request + if (method === "OPTIONS") { + return new Response(null, {headers: corsHeaders}); + } + + if (!query || !query.event_name) + return Response.json( + {error: "event_name is required"}, + {status: 400, headers: corsHeaders} + ); + + // get orgin from headers + const origin: string | null = headers.get("origin"); + if ( + env.ENVIRONMENT === "production" && + (!origin || new URL(origin).hostname !== "www.naveenmk.me") + ) { + return Response.json( + {error: "unauthorized"}, + {status: 401, headers: corsHeaders} + ); + } + + // get the event_name from the query string + const event_name = decodeURIComponent(query.event_name); + + // first see if we can find the event_name in the database + const {results} = await env.DB.prepare( + "SELECT * FROM Events WHERE event_name = ?" + ) + .bind(event_name) + .all(); + if (results.length === 1) { + await env.DB.prepare( + "UPDATE Events SET count = count + 1 WHERE event_name = ?" + ) + .bind(event_name) + .run(); + return Response.json( + {message: "success"}, + {headers: corsHeaders} + ); + } + + // the event_name is not in the database, add it + const insertRes = await env.DB.prepare( + "INSERT INTO Events (event_name) VALUES (?)" + ) + .bind(event_name) + .run(); + if (insertRes.results.length === 1) { + return Response.json({message: "success"}, {headers: corsHeaders}); + } + } +); + router.all("*", () => new Response("404, not found!", {status: 404})); export interface Env { diff --git a/src/api.ts b/src/api.ts new file mode 100644 index 0000000..148a12c --- /dev/null +++ b/src/api.ts @@ -0,0 +1,14 @@ +// use to add events that occur on the website + +export function addEvent(event_name: string) { + if (process.env.NODE_ENV === "production") { + fetch(`https://api.syrusdark.cc/api/add-event?event_name=${event_name}`) + .then(res => res.json()) + .then(json => { + console.log(json); + }) + .catch(e => { + console.error(e); + }); + } +} diff --git a/src/components/freelance-ads/index.tsx b/src/components/freelance-ads/index.tsx index 4dfcffb..3f83b76 100644 --- a/src/components/freelance-ads/index.tsx +++ b/src/components/freelance-ads/index.tsx @@ -3,6 +3,7 @@ import {CloseIcon} from "../icons"; import {createPortal} from "react-dom"; import * as styles from "./freelance-ads.module.scss"; import {useTransition, animated} from "@react-spring/web"; +import {addEvent} from "../../api"; const NUM_DAYS_HIDE = 3; @@ -34,6 +35,19 @@ const FreelanceAds = () => { } }, []); + React.useEffect(() => { + if (!isVisibile) { + return; + } + if (typeof window !== "undefined" && window.gtag) { + window.gtag("event", "show_freelance_ad", { + event_category: "engagement", + event_label: "freelance_ad" + }); + } + addEvent(`show_freelance_ad`); + }, [isVisibile]); + const hideFreeLanceAd = () => { var now = new Date(); var time = now.getTime(); @@ -49,6 +63,8 @@ const FreelanceAds = () => { event_label: "freelance_ad" }); } + + addEvent(`close_freelance_ad`); }; return ( @@ -94,6 +110,9 @@ const FreelanceAds = () => { } ); } + addEvent( + `open_freelance_ad` + ); hideFreeLanceAd(); }} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 8b8f304..3738a21 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -5,6 +5,7 @@ import SEO from "../components/seo.jsx"; // import {StaticImage} from "gatsby-plugin-image"; import {Mail, GitHub, Twitter, Gitlab} from "react-feather"; import Mastodon from "../components/icon/Mastodon"; +import { addEvent } from "../api"; declare global { interface Window { @@ -34,6 +35,7 @@ const SocialLink = ({ event_label: title }); } + addEvent(`open_social_link_${title}`); }} > {children}