mirror of
https://github.com/hwchase17/langchain.git
synced 2025-09-05 13:06:03 +00:00
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:
@@ -1,5 +0,0 @@
|
||||
export default function gtag(...args) {
|
||||
if (window.gtagFeedback) {
|
||||
window.gtagFeedback(...args);
|
||||
}
|
||||
}
|
@@ -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 />
|
||||
|
Reference in New Issue
Block a user