Skip to content

Commit

Permalink
feat(frontend): design changes on user profile (#2140)
Browse files Browse the repository at this point in the history
# Description

Please include a summary of the changes and the related issue. Please
also include relevant motivation and context.

## Checklist before requesting a review

Please delete options that are not relevant.

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented hard-to-understand areas
- [ ] I have ideally added tests that prove my fix is effective or that
my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged

## Screenshots (if appropriate):
  • Loading branch information
Zewed authored Feb 4, 2024
1 parent 7d871d9 commit 8f49a72
Show file tree
Hide file tree
Showing 39 changed files with 574 additions and 207 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from "react";

import { CopyButton } from "@/lib/components/ui/CopyButton";
import Icon from "@/lib/components/ui/Icon/Icon";
import { Source } from "@/lib/types/MessageMetadata";

import styles from "./MessageRow.module.scss";
import { CopyButton } from "./components/CopyButton";
import { MessageContent } from "./components/MessageContent/MessageContent";
import { QuestionBrain } from "./components/QuestionBrain/QuestionBrain";
import { QuestionPrompt } from "./components/QuestionPrompt/QuestionPrompt";
Expand All @@ -26,7 +26,7 @@ export const MessageRow = React.forwardRef(
{ speaker, text, brainName, promptName, children }: MessageRowProps,
ref: React.Ref<HTMLDivElement>
) => {
const { handleCopy, isCopied, isUserSpeaker } = useMessageRow({
const { handleCopy, isUserSpeaker } = useMessageRow({
speaker,
text,
});
Expand Down Expand Up @@ -58,7 +58,7 @@ export const MessageRow = React.forwardRef(
<MessageContent text={messageContent} isUser={isUserSpeaker} />
{!isUserSpeaker && messageContent !== "🧠" && (
<div className={styles.copy_button}>
<CopyButton handleCopy={handleCopy} isCopied={isCopied} />
<CopyButton handleCopy={handleCopy} />
</div>
)}
</>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { useState } from "react";

type UseMessageRowProps = {
speaker: "user" | "assistant";
text?: string;
Expand All @@ -8,22 +6,16 @@ type UseMessageRowProps = {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useMessageRow = ({ speaker, text }: UseMessageRowProps) => {
const isUserSpeaker = speaker === "user";
const [isCopied, setIsCopied] = useState(false);

const handleCopy = () => {
if (text === undefined) {
return;
}
navigator.clipboard.writeText(text).then(
() => setIsCopied(true),
(err) => console.error("Failed to copy!", err)
);
setTimeout(() => setIsCopied(false), 2000); // Reset after 2 seconds
navigator.clipboard.writeText(text).catch((err) => console.error(err));
};

return {
isUserSpeaker,
isCopied,
handleCopy,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@use "@/styles/Spacings.module.scss";

.response_wrapper {
display: flex;
gap: Spacings.$spacing03;
}
52 changes: 21 additions & 31 deletions frontend/app/user/components/ApiKeyConfig/ApiKeyConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,35 @@
"use client";

import { useTranslation } from "react-i18next";
import { FaCopy } from "react-icons/fa";

import Button from "@/lib/components/ui/Button";
import Field from "@/lib/components/ui/Field";
import { CopyButton } from "@/lib/components/ui/CopyButton";
import { FieldHeader } from "@/lib/components/ui/FieldHeader/FieldHeader";

import styles from "./ApiKeyConfig.module.scss";
import { useApiKeyConfig } from "./hooks/useApiKeyConfig";

export const ApiKeyConfig = (): JSX.Element => {
const {
apiKey,
handleCopyClick,
handleCreateClick,

} = useApiKeyConfig();
const { apiKey, handleCopyClick, handleCreateClick } = useApiKeyConfig();
const { t } = useTranslation(["config"]);

return (
<>
<h3 className="font-semibold mb-2">Quivr {t("apiKey")}</h3>

<div>
{apiKey === "" ? (
<Button
data-testid="create-new-key"
variant="secondary"
onClick={() => void handleCreateClick()}
>
Create New Key
</Button>
) : (
<div className="flex items-center space-x-2">
<Field name="quivrApiKey" disabled={true} value={apiKey} />
<button data-testid="copy-api-key-button" onClick={handleCopyClick}>
<FaCopy />
</button>
</div>
)}
</div>

</>
<div>
<FieldHeader iconName="key" label={`Quivr ${t("apiKey")}`} />
{apiKey === "" ? (
<Button
data-testid="create-new-key"
variant="secondary"
onClick={() => void handleCreateClick()}
>
Create New Key
</Button>
) : (
<div className={styles.response_wrapper}>
<span>{apiKey}</span>
<CopyButton handleCopy={handleCopyClick} />
</div>
)}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ export const useApiKeyConfig = () => {
try {
setChangeOpenAiApiKeyRequestPending(true);



await updateUserIdentity({
});
await updateUserIdentity({});
void queryClient.invalidateQueries({
queryKey: [USER_IDENTITY_DATA_KEY],
});
Expand All @@ -85,8 +82,7 @@ export const useApiKeyConfig = () => {
const removeOpenAiApiKey = async () => {
try {
setChangeOpenAiApiKeyRequestPending(true);
await updateUserIdentity({
});
await updateUserIdentity({});

publish({
variant: "success",
Expand All @@ -103,8 +99,6 @@ export const useApiKeyConfig = () => {
}
};



return {
handleCreateClick,
apiKey,
Expand Down
Empty file.
5 changes: 5 additions & 0 deletions frontend/app/user/components/BrainsUsage/BrainsUsage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { UserStatistics } from "../UserStatistics";

export const BrainsUsage = (): JSX.Element => {
return <UserStatistics />;
};
37 changes: 13 additions & 24 deletions frontend/app/user/components/LanguageSelect/LanguageSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,25 @@

import { useTranslation } from "react-i18next";

import { CountrySelector } from "@/lib/components/ui/CountrySelector/CountrySelector";

import { useLanguageHook } from "./hooks/useLanguageHook";

const LanguageSelect = (): JSX.Element => {
const { t } = useTranslation(["translation"]);
const { allLanguages, currentLanguage, change } = useLanguageHook();
const { currentLanguage, change } = useLanguageHook();

if (!currentLanguage) {
return <></>;
}

return (
<fieldset name="language" className="mb-2">
<label
className="block text-slate-700 dark:text-slate-300 mb-2"
htmlFor="language"
>
{t("languageSelect")}
</label>

<select
data-testid="language-select"
name="language"
id="language"
value={currentLanguage}
onChange={(e) => change(e.target.value)}
className="bg-slate-50 focus-visible:ring-0 border rounded dark:bg-black dark:text-white p-2 w-full md:w-1/2 lg:w-1/3"
>
{Object.keys(allLanguages).map((lang) => (
<option data-testid={`option-${lang}`} value={lang} key={lang}>
{allLanguages[lang].label}
</option>
))}
</select>
</fieldset>
<CountrySelector
iconName="flag"
label={t("languageSelect")}
currentValue={currentLanguage}
setCurrentValue={change}
/>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,70 @@ import { useTranslation } from "react-i18next";

import { useEventTracking } from "@/services/analytics/june/useEventTracking";

export const languages = {
en: {
export type Language = {
label: string;
flag: string;
shortName: string;
};

export const languages: Language[] = [
{
label: "English",
flag: "🇬🇧",
shortName: "en",
},
es: {
{
label: "Español",
flag: "🇪🇸",
shortName: "es",
},
fr: {
{
label: "Français",
flag: "🇫🇷",
shortName: "fr",
},
ptbr: {
{
label: "Português",
flag: "🇵🇹",
shortName: "pt",
},
ru: {
{
label: "Русский",
flag: "🇷🇺",
shortName: "ru",
},
zh_cn: {
{
label: "简体中文",
flag: "🇨🇳",
shortName: "zh",
},
};

export type Language = {
[key: string]: {
label: string;
};
};
];

export const useLanguageHook = (): {
change: (newLanguage: string) => void;
allLanguages: Language;
currentLanguage: string | undefined;
change: (newLanguage: Language) => void;
allLanguages: Language[];
currentLanguage: Language | undefined;
} => {
const { i18n } = useTranslation();
const [allLanguages, setAllLanguages] = useState<Language>({});
const [currentLanguage, setCurrentLanguage] = useState<string | undefined>();
const [allLanguages, setAllLanguages] = useState<Language[]>([]);
const [currentLanguage, setCurrentLanguage] = useState<Language>();
const { track } = useEventTracking();

useEffect(() => {
setAllLanguages(languages);
const savedLanguage = localStorage.getItem("selectedLanguage") ?? "English";

// get language from localStorage
const savedLanguage = localStorage.getItem("selectedLanguage") ?? "en";

setCurrentLanguage(savedLanguage);
setCurrentLanguage(
languages.find((language) => language.label === savedLanguage)
);
void i18n.changeLanguage(savedLanguage);
}, [i18n]);

const change = (newLanguage: string) => {
const change = (newLanguage: Language) => {
void track("CHANGE_LANGUAGE");
setCurrentLanguage(newLanguage);
localStorage.setItem("selectedLanguage", newLanguage);
void i18n.changeLanguage(newLanguage);
localStorage.setItem("selectedLanguage", newLanguage.label);
void i18n.changeLanguage(newLanguage.shortName);
};

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useTranslation } from "react-i18next";

import Button from "@/lib/components/ui/Button";
import { Modal } from "@/lib/components/ui/Modal";
import TextButton from "@/lib/components/ui/TextButton/TextButton";

import { useLogoutModal } from "./hooks/useLogoutModal";

Expand All @@ -17,9 +18,13 @@ export const LogoutModal = (): JSX.Element => {
return (
<Modal
Trigger={
<Button className="px-3 py-2" variant="secondary">
{t("logoutButton")}
</Button>
<div onClick={() => void 0}>
<TextButton
iconName="logout"
color="dangerous"
label={t("logoutButton")}
/>
</div>
}
isOpen={isLogoutModalOpened}
setOpen={setIsLogoutModalOpened}
Expand Down
Empty file.
9 changes: 9 additions & 0 deletions frontend/app/user/components/Plan/Plan.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { StripePricingOrManageButton } from "../StripePricingOrManageButton";

export const Plan = (): JSX.Element => {
return (
<div>
<StripePricingOrManageButton />
</div>
);
};
12 changes: 12 additions & 0 deletions frontend/app/user/components/Settings/Settings.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@use "@/styles/Radius.module.scss";
@use "@/styles/Spacings.module.scss";

.settings_wrapper {
display: flex;
flex-direction: column;
gap: Spacings.$spacing07;
width: auto;
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.25);
border-radius: Radius.$big;
padding: Spacings.$spacing05;
}
Loading

0 comments on commit 8f49a72

Please sign in to comment.