docs[minor]: Swap gtag for supabase (#18937)

Added deps:
- `@supabase/supabase-js` - for sending inserts
- `supabase` - dev dep, for generating types via cli
- `dotenv` for loading env vars

Added script:
- `yarn gen` - will auto generate the database schema types using the
supabase CLI. Not necessary for development, but is useful. Requires
authing with the supabase CLI (will error out w/ instructions if you're
not authed).

Added functionality:
- pulls users IP address (using a free endpoint: `https://api.ipify.org`
so we can filter out abuse down the line)

TODO:
- [x] add env vars to vercel
This commit is contained in:
Brace Sproul
2024-03-11 14:23:12 -07:00
committed by GitHub
parent 5c2f7e6b2b
commit 4ff6aa5c78
8 changed files with 274 additions and 15840 deletions

View File

@@ -1,5 +0,0 @@
export default function gtag(...args) {
if (window.gtagFeedback) {
window.gtagFeedback(...args);
}
}

View File

@@ -1,6 +1,6 @@
/* eslint-disable no-return-assign, react/jsx-props-no-spreading */
import React, { useState, useEffect } from "react";
import gtag from "../analytics";
import { createClient } from "@supabase/supabase-js";
const useCookie = () => {
/**
@@ -90,27 +90,69 @@ function SvgThumbsDown() {
);
}
/**
* Generated type for the Supabase DB schema.
* @typedef {import('../supabase').Database} Database
*/
const FEEDBACK_COOKIE_PREFIX = "feedbackSent";
/** @type {Database["public"]["Enums"]["project_type"]} */
const LANGCHAIN_PROJECT_NAME = "langchain_py_docs";
/**
* @returns {Promise<string>}
*/
const getIpAddress = async () => {
const response = await fetch("https://api.ipify.org?format=json");
return (await response.json()).ip;
};
export default function Feedback() {
const { setCookie, checkCookie } = useCookie();
const [feedbackSent, setFeedbackSent] = useState(false);
/**
* @param {"good" | "bad"} feedback
*/
const handleFeedback = (feedback) => {
/** @param {"good" | "bad"} feedback */
const handleFeedback = async (feedback) => {
if (process.env.NODE_ENV !== "production") {
console.log("Feedback (dev)");
return;
}
const cookieName = `${FEEDBACK_COOKIE_PREFIX}_${window.location.pathname}`;
if (checkCookie(cookieName)) {
return;
}
const feedbackEnv =
process.env.NODE_ENV === "production"
? "page_feedback"
: "page_feedback_dev";
/** @type {Database} */
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_PUBLIC_KEY
);
try {
const ipAddress = await getIpAddress();
/**
* "id" and "created_at" are automatically generated by Supabase
* @type {Omit<Database["public"]["Tables"]["feedback"]["Row"], "id" | "created_at">}
*/
const data = {
is_good: feedback === "good",
url: window.location.pathname,
user_ip: ipAddress,
project: LANGCHAIN_PROJECT_NAME,
};
const { error } = await supabase.from("feedback").insert(data);
if (error) {
throw error;
}
} catch (e) {
console.error("Failed to send feedback", {
e,
});
return;
}
gtag("event", `${feedbackEnv}_${feedback}`, {});
// Set a cookie to prevent feedback from being sent multiple times
setCookie(cookieName, window.location.pathname, 1);
setFeedbackSent(true);
@@ -161,16 +203,16 @@ export default function Feedback() {
{...defaultFields}
role="button" // Make it recognized as an interactive element
tabIndex={0} // Make it focusable
onKeyDown={(e) => {
onKeyDown={async (e) => {
// Handle keyboard interaction
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleFeedback("good");
await handleFeedback("good");
}
}}
onClick={(e) => {
onClick={async (e) => {
e.preventDefault();
handleFeedback("good");
await handleFeedback("good");
}}
>
<SvgThumbsUp />
@@ -179,16 +221,16 @@ export default function Feedback() {
{...defaultFields}
role="button" // Make it recognized as an interactive element
tabIndex={0} // Make it focusable
onKeyDown={(e) => {
onKeyDown={async (e) => {
// Handle keyboard interaction
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleFeedback("bad");
await handleFeedback("bad");
}
}}
onClick={(e) => {
onClick={async (e) => {
e.preventDefault();
handleFeedback("bad");
await handleFeedback("bad");
}}
>
<SvgThumbsDown />