Skip to content

Commit

Permalink
Add in tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
adamjarling committed Mar 4, 2024
1 parent 31f7df8 commit a38d9e3
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 37 deletions.
12 changes: 6 additions & 6 deletions components/Chat/components/Answer/Information.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import * as Tooltip from "@radix-ui/react-tooltip";

import React from "react";
import { styled } from "@/stitches.config";

interface AnswerInformationProps {
timestamp: number;
}

export const generativeAIWarning = `The answers and provided links are generated using chatGPT and metadata from Northwestern University Libraries Digital Collections. This is an experiment and results may be inaccurate, irrelevant, or potentially harmful.`;

export const AnswerInformation: React.FC<AnswerInformationProps> = ({
timestamp,
}) => {
Expand All @@ -32,10 +35,7 @@ export const AnswerInformation: React.FC<AnswerInformationProps> = ({
<Tooltip.Content side="bottom" sideOffset={3} collisionPadding={19}>
<AnswerTooltipArrow />
<AnswerTooltipContent>
The answers and provided links are generated using chatGPT and
metadata from Northwestern University Libraries Digital
Collections. This is an experiment and results may be
inaccurate, irrelevant, or potentially harmful.
{generativeAIWarning}
<em>Answered on {answerDate}</em>
</AnswerTooltipContent>
</Tooltip.Content>
Expand Down Expand Up @@ -71,11 +71,11 @@ export const AnswerTooltip = styled("span", {
},
});

const AnswerTooltipArrow = styled(Tooltip.Arrow, {
export const AnswerTooltipArrow = styled(Tooltip.Arrow, {
fill: "$brightBlueB",
});

const AnswerTooltipContent = styled("div", {
export const AnswerTooltipContent = styled("div", {
background: "$white",
boxShadow: "0 13px 21px 0 rgba(0, 0, 0, 0.13)",
width: "450px",
Expand Down
62 changes: 49 additions & 13 deletions components/Search/GenerativeAIToggle.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,60 @@
import * as Tooltip from "@radix-ui/react-tooltip";

import {
AnswerTooltipArrow,
AnswerTooltipContent,
generativeAIWarning,
} from "@/components/Chat/components/Answer/Information";
import {
Button,
CheckboxIndicator,
CheckboxRoot,
GenerativeAIDialogMessage,
GenerativeAIToggleWrapper,
} from "./Search.styled";
} from "@/components/Search/Search.styled";

import { DCAPI_ENDPOINT } from "@/lib/constants/endpoints";
import { Button } from "@nulib/design-system";
import GenerativeAIDialog from "@/components/Shared/Dialog";
import { IconCheck } from "@/components/Shared/SVG/Icons";
import { IconInfo } from "@/components/Shared/SVG/Icons";
import React from "react";
import { styled } from "@/stitches.config";
import useGenerativeAISearchToggle from "@/hooks/useGenerativeAISearchToggle";

const TooltipTrigger = styled(Tooltip.Trigger, {
background: "transparent",
border: "none",
});

const TooltipContent = styled(Tooltip.Content, {
zIndex: 10,
});

function GenerativeAITooltip() {
return (
<Tooltip.Provider delayDuration={20}>
<Tooltip.Root>
<TooltipTrigger>
<IconInfo />
</TooltipTrigger>
<Tooltip.Portal>
<TooltipContent side="bottom" sideOffset={3} collisionPadding={19}>
<AnswerTooltipArrow />
<AnswerTooltipContent>{generativeAIWarning}</AnswerTooltipContent>
</TooltipContent>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
);
}

type GenerativeAIToggleProps = {
isSearchActive: boolean;
};

export default function GenerativeAIToggle({
isSearchActive,
}: GenerativeAIToggleProps) {
const { closeDialog, dialog, goToUrl, isChecked, handleCheckChange } =
const { closeDialog, dialog, isChecked, handleCheckChange, handleLogin } =
useGenerativeAISearchToggle();

return (
Expand All @@ -37,21 +72,22 @@ export default function GenerativeAIToggle({
</CheckboxIndicator>
</CheckboxRoot>
<label htmlFor="isGenerativeAI">Use Generative AI</label>

<IconInfo />
<GenerativeAITooltip />
</GenerativeAIToggleWrapper>

<GenerativeAIDialog
isOpen={dialog.isOpen}
title={dialog.title}
handleCloseClick={closeDialog}
>
<p>
<a href={`${DCAPI_ENDPOINT}/auth/login?goto=${goToUrl()}`}>
Click here
</a>{" "}
to login
</p>
<Button>Close</Button>
<GenerativeAIDialogMessage>
You must be logged in with a Northwestern NetID to use the Generative
AI search feature.
</GenerativeAIDialogMessage>
<Button isPrimary onClick={handleLogin}>
Login
</Button>
<Button onClick={closeDialog}>Cancel</Button>
</GenerativeAIDialog>
</>
);
Expand Down
5 changes: 5 additions & 0 deletions components/Search/Search.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ const GenerativeAIToggleWrapper = styled("div", {
},
});

const GenerativeAIDialogMessage = styled("p", {
marginBottom: "$gr4",
});

const CheckboxRoot = styled(Checkbox.Root, {
display: "flex",
marginRight: "$gr1",
Expand Down Expand Up @@ -207,6 +211,7 @@ export {
CheckboxRoot,
CheckboxIndicator,
Clear,
GenerativeAIDialogMessage,
GenerativeAIToggleWrapper,
Input,
NoResultsMessage,
Expand Down
3 changes: 3 additions & 0 deletions hooks/useChatSocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { useEffect, useState } from "react";
import { DCAPI_CHAT_ENDPOINT } from "@/lib/constants/endpoints";
import axios from "axios";

// URL which the browser seems to have to hit to authenticate with the chat endpoint
// https://api.dc.library.northwestern.edu/api/v2/auth/login?goto=https://api.dc.library.northwestern.edu/api/v2/chat-endpoint

const useChatSocket = () => {
const [chatSocket, setChatSocket] = useState<WebSocket | null>(null);
const [authToken, setAuthToken] = useState<string | null>(null);
Expand Down
56 changes: 38 additions & 18 deletions hooks/useGenerativeAISearchToggle.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,46 @@
import React, { useEffect, useState } from "react";

import { DCAPI_ENDPOINT } from "@/lib/constants/endpoints";
import { UserContext } from "@/context/user-context";
import { useRouter } from "next/router";
import { useSearchState } from "@/context/search-context";

const defaultModalState = {
isOpen: false,
title: "Generative AI Dialog",
title: "Use Generative AI",
};

const aiQueryParam = "ai";

export default function useGenerativeAISearchToggle() {
const router = useRouter();
const effectQueryDep = router.query[aiQueryParam];

const { searchState, searchDispatch } = useSearchState();
const { user } = React.useContext(UserContext);
const router = useRouter();

const [dialog, setDialog] = useState(defaultModalState);
const [isChecked, setIsChecked] = useState<boolean>(
searchState.isGenerativeAI
);

const handleCheckChange = (checked: boolean) => {
const loginUrl = `${DCAPI_ENDPOINT}/auth/login?goto=${goToLocation()}`;

// TODO: This needs to accept more than one query param when
// directing to NU SSO. We need the additional query param
// to know that user came wanting to use Generative AI
function goToLocation() {
const currentUrl = `${window.location.origin}${router.asPath}`;
const url = new URL(currentUrl);
url.searchParams.set(aiQueryParam, "true");
return url.toString();
}

function closeDialog() {
setDialog({ ...dialog, isOpen: false });
}

function handleCheckChange(checked: boolean) {
if (!user?.isLoggedIn) {
setDialog({ ...dialog, isOpen: checked });
}
Expand All @@ -30,31 +51,30 @@ export default function useGenerativeAISearchToggle() {
type: "updateGenerativeAI",
});
}
};
}

function handleLogin() {
router.push(loginUrl);
}

useEffect(() => {
setIsChecked(searchState.isGenerativeAI);
}, [searchState.isGenerativeAI]);

// TODO: This needs to accept more than one query param when
// directing to NU SSO. We need the additional query param
// to know that user came wanting to use Generative AI
function goToLocation() {
const currentUrl = `${window.location.origin}${router.asPath}`;
const url = new URL(currentUrl);
url.searchParams.set("ai", "true");
return url.toString();
}

function closeDialog() {
setDialog({ ...dialog, isOpen: false });
}
useEffect(() => {
if (effectQueryDep && user?.isLoggedIn) {
searchDispatch({
isGenerativeAI: true,
type: "updateGenerativeAI",
});
}
}, [effectQueryDep, searchDispatch, user?.isLoggedIn]);

return {
closeDialog,
dialog,
goToUrl: goToLocation,
handleCheckChange,
handleLogin,
isChecked,
};
}

0 comments on commit a38d9e3

Please sign in to comment.