Merge branch 'preview/advisors' into 'develop'
Preview/advisors See merge request witapp/aura-webapp!75
This commit is contained in:
commit
d381440556
@ -26,7 +26,7 @@ import {
|
|||||||
AIRequestsV2,
|
AIRequestsV2,
|
||||||
Assistants,
|
Assistants,
|
||||||
OpenAI,
|
OpenAI,
|
||||||
SinglePayment
|
SinglePayment,
|
||||||
} from './resources'
|
} from './resources'
|
||||||
|
|
||||||
const api = {
|
const api = {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Routes,
|
Routes,
|
||||||
Route,
|
Route,
|
||||||
@ -109,6 +109,7 @@ import AdvisorChatPage from "../pages/AdvisorChat";
|
|||||||
import PaymentWithEmailPage from "../pages/PaymentWithEmailPage";
|
import PaymentWithEmailPage from "../pages/PaymentWithEmailPage";
|
||||||
import SuccessPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/SuccessPaymentPage";
|
import SuccessPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/SuccessPaymentPage";
|
||||||
import FailPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/FailPaymentPage";
|
import FailPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/FailPaymentPage";
|
||||||
|
import { useSchemeColorByElement } from "@/hooks/useSchemeColorByElement";
|
||||||
import GetInformationPartnerPage from "../pages/GetInformationPartner";
|
import GetInformationPartnerPage from "../pages/GetInformationPartner";
|
||||||
|
|
||||||
const isProduction = import.meta.env.MODE === "production";
|
const isProduction = import.meta.env.MODE === "production";
|
||||||
@ -228,6 +229,26 @@ function App(): JSX.Element {
|
|||||||
}
|
}
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// const motion = window.matchMedia("(prefers-reduced-motion: no-preference)");
|
||||||
|
// if (motion.matches) {
|
||||||
|
// const scheme = document.querySelector('meta[name="theme-color"]');
|
||||||
|
// console.log(document.querySelectorAll("section.page")[0]);
|
||||||
|
// let hue = 0;
|
||||||
|
// let color;
|
||||||
|
// const backgroundColor =
|
||||||
|
// window.getComputedStyle(document.querySelectorAll("section.page")[0])
|
||||||
|
// .backgroundColor || "#ffffff";
|
||||||
|
// scheme?.setAttribute("content", backgroundColor);
|
||||||
|
|
||||||
|
// setInterval(() => {
|
||||||
|
// color = `hsl(${(hue += 5)} 50% 30%)`;
|
||||||
|
// document.body.style.background = color;
|
||||||
|
// scheme?.setAttribute("content", color);
|
||||||
|
// }, 50);
|
||||||
|
// }
|
||||||
|
// }, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}>
|
<Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}>
|
||||||
@ -550,6 +571,19 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
|
|||||||
const changeIsSpecialOfferOpen = () => setIsSpecialOfferOpen(true);
|
const changeIsSpecialOfferOpen = () => setIsSpecialOfferOpen(true);
|
||||||
const homeConfig = useSelector(selectors.selectHome);
|
const homeConfig = useSelector(selectors.selectHome);
|
||||||
const showNavbarFooter = homeConfig.isShowNavbar;
|
const showNavbarFooter = homeConfig.isShowNavbar;
|
||||||
|
const mainRef = useRef<HTMLDivElement>(null);
|
||||||
|
// console.log(
|
||||||
|
// mainRef.current?.querySelectorAll("section.page, .page, section")
|
||||||
|
// );
|
||||||
|
useSchemeColorByElement(mainRef.current, "section.page, .page, section", [
|
||||||
|
location,
|
||||||
|
]);
|
||||||
|
// useEffect(() => {
|
||||||
|
// console.log(
|
||||||
|
// "###$",
|
||||||
|
// mainRef.current?.querySelectorAll("section.page, .page, section")[0]
|
||||||
|
// );
|
||||||
|
// }, [location]);
|
||||||
|
|
||||||
const birthdate = useSelector(selectors.selectBirthdate);
|
const birthdate = useSelector(selectors.selectBirthdate);
|
||||||
const dataItems = useMemo(() => [birthdate], [birthdate]);
|
const dataItems = useMemo(() => [birthdate], [birthdate]);
|
||||||
@ -644,7 +678,7 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
|
|||||||
<FullDataModal onClose={onCloseFullDataModal} />
|
<FullDataModal onClose={onCloseFullDataModal} />
|
||||||
</Modal>
|
</Modal>
|
||||||
)}
|
)}
|
||||||
<main className="content">
|
<main className="content" ref={mainRef}>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</main>
|
</main>
|
||||||
{showFooter ? <Footer color={showNavbar ? "black" : "white"} /> : null}
|
{showFooter ? <Footer color={showNavbar ? "black" : "white"} /> : null}
|
||||||
|
|||||||
@ -29,3 +29,12 @@
|
|||||||
.page-responsive {
|
.page-responsive {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#color-pointer {
|
||||||
|
position: fixed;
|
||||||
|
background: transparent;
|
||||||
|
z-index: 12323423;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { IMessage, ResponseRunThread } from "@/api/resources/OpenAI";
|
|||||||
import Message from "./components/Message";
|
import Message from "./components/Message";
|
||||||
import LoaderDots from "./components/LoaderDots";
|
import LoaderDots from "./components/LoaderDots";
|
||||||
import useDetectScroll from "@smakss/react-scroll-direction";
|
import useDetectScroll from "@smakss/react-scroll-direction";
|
||||||
|
import { getZodiacSignByDate } from "@/services/zodiac-sign";
|
||||||
|
|
||||||
function AdvisorChatPage() {
|
function AdvisorChatPage() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@ -21,6 +22,10 @@ function AdvisorChatPage() {
|
|||||||
const { scrollDir, scrollPosition } = useDetectScroll();
|
const { scrollDir, scrollPosition } = useDetectScroll();
|
||||||
const token = useSelector(selectors.selectToken);
|
const token = useSelector(selectors.selectToken);
|
||||||
const openAiToken = useSelector(selectors.selectOpenAiToken);
|
const openAiToken = useSelector(selectors.selectOpenAiToken);
|
||||||
|
const birthdate = useSelector(selectors.selectBirthdate);
|
||||||
|
const zodiacSign = getZodiacSignByDate(birthdate);
|
||||||
|
const { username } = useSelector(selectors.selectUser);
|
||||||
|
const { gender } = useSelector(selectors.selectQuestionnaire);
|
||||||
const [assistant, setAssistant] = useState<IAssistant>();
|
const [assistant, setAssistant] = useState<IAssistant>();
|
||||||
const [messageText, setMessageText] = useState("");
|
const [messageText, setMessageText] = useState("");
|
||||||
const [textareaRows, setTextareaRows] = useState(1);
|
const [textareaRows, setTextareaRows] = useState(1);
|
||||||
@ -192,12 +197,15 @@ function AdvisorChatPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createMessage = async (messageText: string, threadId: string) => {
|
const createMessage = async (messageText: string, threadId: string) => {
|
||||||
|
const content = `#USER INFO: zodiac sign - ${zodiacSign}; gender - ${gender}; birthdate - ${birthdate}; name - ${
|
||||||
|
username || "unknown"
|
||||||
|
};# ${messageText}`;
|
||||||
const message = await api.createMessage({
|
const message = await api.createMessage({
|
||||||
token: openAiToken,
|
token: openAiToken,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: routes.openAi.createMessage(threadId),
|
path: routes.openAi.createMessage(threadId),
|
||||||
role: "user",
|
role: "user",
|
||||||
content: messageText,
|
content: content,
|
||||||
});
|
});
|
||||||
return message;
|
return message;
|
||||||
};
|
};
|
||||||
@ -294,6 +302,14 @@ function AdvisorChatPage() {
|
|||||||
|
|
||||||
const getIsSelfMessage = (role: string) => role === "user";
|
const getIsSelfMessage = (role: string) => role === "user";
|
||||||
|
|
||||||
|
const deleteDataFromMessage = (messageText: string) => {
|
||||||
|
const splittedText = messageText.split("#");
|
||||||
|
if (splittedText.length > 2) {
|
||||||
|
return splittedText.slice(2).join("#");
|
||||||
|
}
|
||||||
|
return messageText;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`${styles.page} page`}>
|
<section className={`${styles.page} page`}>
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
@ -322,7 +338,7 @@ function AdvisorChatPage() {
|
|||||||
message.content.map((content) => (
|
message.content.map((content) => (
|
||||||
<Message
|
<Message
|
||||||
avatar={assistant?.photo?.th2x || ""}
|
avatar={assistant?.photo?.th2x || ""}
|
||||||
text={content.text.value}
|
text={deleteDataFromMessage(content.text.value)}
|
||||||
advisorName={assistant?.name || ""}
|
advisorName={assistant?.name || ""}
|
||||||
backgroundTextColor={
|
backgroundTextColor={
|
||||||
getIsSelfMessage(message.role) ? "#0080ff" : "#c9c9c9"
|
getIsSelfMessage(message.role) ? "#0080ff" : "#c9c9c9"
|
||||||
|
|||||||
@ -27,7 +27,7 @@ function AssistantCard({
|
|||||||
</Title>
|
</Title>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.footer}>
|
<div className={styles.footer}>
|
||||||
<span className={styles.expirience}>{expirience}</span>
|
<span className={styles.experience}>{expirience}</span>
|
||||||
<div className={styles["rating-container"]}>
|
<div className={styles["rating-container"]}>
|
||||||
<div className={styles.stars}>
|
<div className={styles.stars}>
|
||||||
{Array(stars)
|
{Array(stars)
|
||||||
|
|||||||
@ -70,10 +70,11 @@
|
|||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expirience {
|
.experience {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
display: block;
|
display: block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
line-height: 150%;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ function Advisors() {
|
|||||||
setAssistants(ai_assistants);
|
setAssistants(ai_assistants);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
return { ai_assistants };
|
return { ai_assistants };
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [api, dispatch, token]);
|
}, [api, dispatch, token]);
|
||||||
|
|
||||||
useApiCall<Assistants.Response>(loadData);
|
useApiCall<Assistants.Response>(loadData);
|
||||||
|
|||||||
@ -13,7 +13,7 @@ function SuccessPaymentPage(): JSX.Element {
|
|||||||
style={{ minHeight: "98px" }}
|
style={{ minHeight: "98px" }}
|
||||||
/>
|
/>
|
||||||
<div className={styles.text}>
|
<div className={styles.text}>
|
||||||
<Title variant="h1">The information has been sent to your e-mail</Title>
|
<Title variant="h1">The information has been sent to your email</Title>
|
||||||
<p>{t("auweb.pay_good.text1")}</p>
|
<p>{t("auweb.pay_good.text1")}</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
30
src/hooks/useSchemeColorByElement.tsx
Normal file
30
src/hooks/useSchemeColorByElement.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { getValuesFromRGBString } from "@/services/color-formatter";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
export const useSchemeColorByElement = (
|
||||||
|
element: Element | null,
|
||||||
|
searchSelectors: string,
|
||||||
|
dependencies: ReadonlyArray<unknown> = []
|
||||||
|
) => {
|
||||||
|
useEffect(() => {
|
||||||
|
const pageElement = element?.querySelectorAll(searchSelectors)[0];
|
||||||
|
console.log("pageElement", pageElement);
|
||||||
|
|
||||||
|
const scheme = document.querySelector('meta[name="theme-color"]');
|
||||||
|
if (scheme && !pageElement) {
|
||||||
|
return scheme.setAttribute("content", "#ffffff");
|
||||||
|
}
|
||||||
|
if (!pageElement) return;
|
||||||
|
let backgroundColor = window.getComputedStyle(pageElement)?.backgroundColor;
|
||||||
|
const colorScheme = getValuesFromRGBString(backgroundColor);
|
||||||
|
if (colorScheme?.a === 0) {
|
||||||
|
backgroundColor = "#ffffff";
|
||||||
|
}
|
||||||
|
console.log("backgroundColor", backgroundColor);
|
||||||
|
if (scheme && backgroundColor.length) {
|
||||||
|
return scheme.setAttribute("content", backgroundColor);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [element, ...dependencies]);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
44
src/services/color-formatter/index.ts
Normal file
44
src/services/color-formatter/index.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
const hexToRgb = (hex: string) => {
|
||||||
|
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
||||||
|
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||||
|
hex = hex.replace(shorthandRegex, function (_m, r, g, b) {
|
||||||
|
return r + r + g + g + b + b;
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||||
|
return result
|
||||||
|
? {
|
||||||
|
r: parseInt(result[1], 16),
|
||||||
|
g: parseInt(result[2], 16),
|
||||||
|
b: parseInt(result[3], 16),
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IRGBValues {
|
||||||
|
r: number;
|
||||||
|
g: number;
|
||||||
|
b: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rgbToHex = ({ r, g, b }: IRGBValues) => {
|
||||||
|
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getValuesFromRGBString = (rgb: string) => {
|
||||||
|
const rgbValues = rgb.match(/\d+/g);
|
||||||
|
if (rgbValues) {
|
||||||
|
return {
|
||||||
|
r: Number(rgbValues[0]),
|
||||||
|
g: Number(rgbValues[1]),
|
||||||
|
b: Number(rgbValues[2]),
|
||||||
|
a: Number(rgbValues[3] || 1),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class ColorFormatter {
|
||||||
|
public static rgbToHex = rgbToHex;
|
||||||
|
public static hexToRgb = hexToRgb;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user