diff --git a/package-lock.json b/package-lock.json index 7dc0036..47ee7fe 100755 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "html-react-parser": "^3.0.16", "i18next": "^22.5.0", "i18next-react-postprocessor": "^3.1.0", + "moment": "^2.30.1", "react": "^18.2.0", "react-circular-progressbar": "^2.1.0", "react-dom": "^18.2.0", @@ -2665,6 +2666,14 @@ "node": "*" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -5381,6 +5390,11 @@ "brace-expansion": "^1.1.7" } }, + "moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/package.json b/package.json index 965f5b4..f5b2c41 100755 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "html-react-parser": "^3.0.16", "i18next": "^22.5.0", "i18next-react-postprocessor": "^3.1.0", + "moment": "^2.30.1", "react": "^18.2.0", "react-circular-progressbar": "^2.1.0", "react-dom": "^18.2.0", diff --git a/src/api/api.ts b/src/api/api.ts index ca2c811..963151a 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -34,6 +34,7 @@ const api = { auth: createMethod(AuthTokens.createRequest), appleAuth: createMethod(AppleAuth.createRequest), googleAuth: createMethod(GoogleAuth.createRequest), + getRealToken: createMethod(AuthTokens.createGetRealTokenRequest), getAppConfig: createMethod(Apps.createRequest), getElement: createMethod(Element.createRequest), getElements: createMethod(Elements.createRequest), @@ -72,6 +73,8 @@ const api = { createSinglePayment: createMethod(SinglePayment.createRequestPost), checkProductPurchased: createMethod(Products.createRequest), getPalmistryLines: createMethod(Palmistry.createRequest), + // New Authorization + authorization: createMethod(User.createAuthorizeRequest), } export type ApiContextValue = typeof api diff --git a/src/api/resources/AuthTokens.ts b/src/api/resources/AuthTokens.ts index 748631d..18c72f6 100644 --- a/src/api/resources/AuthTokens.ts +++ b/src/api/resources/AuthTokens.ts @@ -1,7 +1,7 @@ import routes from "@/routes"; import { AuthToken } from "../types"; import { User } from "./User"; -import { getBaseHeaders } from "../utils"; +import { getAuthHeaders, getBaseHeaders } from "../utils"; export interface PayloadRegisterByEmail { email: string; @@ -41,3 +41,16 @@ export const createRequest = (payload: Payload): Request => { const body = JSON.stringify({ auth: { ...payload } }); return new Request(url, { method: "POST", headers: getBaseHeaders(), body }); }; + +export interface PayloadGetRealToken { + token: string; +} + +export interface ResponseGetRealToken { + token: string; +} + +export const createGetRealTokenRequest = ({ token }: PayloadGetRealToken): Request => { + const url = new URL(routes.server.dApiGetRealToken()); + return new Request(url, { method: "POST", headers: getAuthHeaders(token) }); +} \ No newline at end of file diff --git a/src/api/resources/User.ts b/src/api/resources/User.ts index 2bab6eb..34e5e88 100644 --- a/src/api/resources/User.ts +++ b/src/api/resources/User.ts @@ -1,6 +1,6 @@ import routes from "@/routes"; import { AuthPayload } from "../types"; -import { getAuthHeaders } from "../utils"; +import { getAuthHeaders, getBaseHeaders } from "../utils"; export type GetPayload = AuthPayload; @@ -130,3 +130,57 @@ export const createPatchRequest = ({ token, user }: PatchPayload): Request => { body, }); }; + +export enum ESourceAuthorization { + "aura.main" = "aura.main", + "aura.palmistry" = "aura.palmistry", + "aura.chat" = "aura.chat", + "aura.moons" = "aura.moons" +} + +export enum EGender { + "male" = "male", + "female" = "female", + "other" = "other" +} + +enum ERelationshipStatus { + "single", + "relationship", + "married", + "complicated", + "other" +} + +interface ICreateAuthorizeUser { + name: string; + birthdate: string | null; + gender: EGender; + birthplace: { + address?: string; + coords?: string; + } + relationship_status: ERelationshipStatus; +} + +export interface ICreateAuthorizePayload { + email: string; + locale: string; + timezone: string; + source: ESourceAuthorization; + profile?: Partial; + partner?: Partial>; +} + +export interface ICreateAuthorizeResponse { + token: string; +} + +export const createAuthorizeRequest = (data: ICreateAuthorizePayload): Request => { + const body = JSON.stringify(data); + return new Request(routes.server.dApiAuth(), { + method: "POST", + headers: getBaseHeaders(), + body, + }); +} \ No newline at end of file diff --git a/src/components/App/index.tsx b/src/components/App/index.tsx index f834438..2d70791 100755 --- a/src/components/App/index.tsx +++ b/src/components/App/index.tsx @@ -198,11 +198,14 @@ function App(): JSX.Element { (async () => { if (!jwtToken) return; logout(); - const auth = await api.auth({ jwt: jwtToken }); - const { - auth: { token, user }, - } = auth; - signUp(token, user); + try { + const { token } = await api.getRealToken({ token: jwtToken }); + const { user } = await api.getUser({ token }); + signUp(token, user); + } catch (error) { + console.log("Error of get real token or get user: "); + console.error(error); + } })(); }, [api, jwtToken, logout, signUp]); @@ -318,6 +321,9 @@ function App(): JSX.Element { no: routes.client.epeGender(), force: routes.client.epeBirthdate(), }, + purchasedProduct: { + no: routes.client.epePayment(), + }, }} requiredParameters={[birthdate, isForceShortPath || gender]} /> @@ -487,6 +493,9 @@ function App(): JSX.Element { no: routes.client.advisorChatGender(), force: routes.client.advisorChatBirthdate(), }, + purchasedProduct: { + no: routes.client.advisorChatPayment(), + }, }} requiredParameters={[ birthdate, @@ -1075,6 +1084,7 @@ interface IShortPathOutletProps { function ShortPathOutlet(props: IShortPathOutletProps): JSX.Element { const { productKey, requiredParameters, redirectUrls, isProductPage } = props; const { user, token } = useAuth(); + const api = useApi(); const isForce = useSelector(selectors.selectIsForceShortPath); diff --git a/src/components/EmailEnterPage/index.tsx b/src/components/EmailEnterPage/index.tsx index 13d7228..8ee524c 100755 --- a/src/components/EmailEnterPage/index.tsx +++ b/src/components/EmailEnterPage/index.tsx @@ -4,18 +4,17 @@ import { useNavigate, useParams } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { useDispatch, useSelector } from "react-redux"; import { actions, selectors } from "@/store"; -import { getClientTimezone } from "@/locales"; -import { useAuth } from "@/auth"; -import { useApi, ApiError, extractErrorMessage } from "@/api"; +import { useApi } from "@/api"; import Title from "../Title"; import Policy from "../Policy"; import EmailInput from "./EmailInput"; import MainButton from "../MainButton"; import Loader, { LoaderColor } from "../Loader"; -import ErrorText from "../ErrorText"; import routes from "@/routes"; import NameInput from "./NameInput"; import { ISubscriptionPlan } from "@/api/resources/SubscriptionPlans"; +import { useAuthentication } from "@/hooks/authentication/use-authentication"; +import { ESourceAuthorization } from "@/api/resources/User"; interface IEmailEnterPage { redirectUrl?: string; @@ -27,33 +26,23 @@ function EmailEnterPage({ isRequiredName = false, }: IEmailEnterPage): JSX.Element { const api = useApi(); - const { signUp } = useAuth(); const { t, i18n } = useTranslation(); const dispatch = useDispatch(); const navigate = useNavigate(); const [email, setEmail] = useState(""); const [name, setName] = useState(""); - const birthday = useSelector(selectors.selectBirthday); const [isDisabled, setIsDisabled] = useState(true); const [isValidEmail, setIsValidEmail] = useState(false); const [isValidName, setIsValidName] = useState(!isRequiredName); - const [isLoading, setIsLoading] = useState(false); const [isAuth, setIsAuth] = useState(false); - const [apiError, setApiError] = useState(null); - const [error, setError] = useState(false); const [subPlans, setSubPlans] = useState([]); const activeSubPlanFromStore = useSelector(selectors.selectActiveSubPlan); const [activeSubPlan, setActiveSubPlan] = useState( activeSubPlanFromStore ); - const timezone = getClientTimezone(); const locale = i18n.language; const { subPlan } = useParams(); - const { - gender, - birthPlace, - // flowChoice - } = useSelector(selectors.selectQuestionnaire); + const { error, isLoading, authorization } = useAuthentication(); useEffect(() => { if (subPlan) { @@ -99,6 +88,13 @@ function EmailEnterPage({ }; const handleValidName = (name: string) => { + if (name) { + dispatch( + actions.user.update({ + username: name, + }) + ); + } setName(name); setIsValidName(true); }; @@ -112,62 +108,27 @@ function EmailEnterPage({ }, [isValidEmail, isValidName, email, name]); const handleClick = () => { - authorization(); + authorize(); }; - const authorization = async () => { - try { - setIsLoading(true); - const auth = await api.auth({ email, timezone, locale }); - const { - auth: { token, user }, - } = auth; - signUp(token, user); - const payload = { - user: { - profile_attributes: { - birthday, - gender: gender.length ? gender : "male", - full_name: name, - // relationship_status: !!flowChoice.length ? flowChoice : null, - }, - birthplace_attributes: { address: birthPlace }, - }, - token, - }; - const updatedUser = await api.updateUser(payload).catch((error) => { - console.log("Error: ", error); - }); - if (updatedUser?.user) { - dispatch(actions.user.update(updatedUser.user)); - } - if (name) { - dispatch( - actions.user.update({ - username: name, - }) - ); - } - dispatch(actions.status.update("registred")); - dispatch( - actions.payment.update({ - activeSubPlan, - }) - ); - setIsLoading(false); - setIsAuth(true); - setTimeout(() => { - navigate(redirectUrl); - }, 1000); - } catch (error) { - console.error(error); - if (error instanceof ApiError) { - setApiError(error as ApiError); - } else { - setError(true); - } - setIsLoading(false); + const authorize = async () => { + let source = ESourceAuthorization["aura.main"]; + if (window.location.pathname.includes("advisor-chat")) { + source = ESourceAuthorization["aura.chat"]; } + if (window.location.pathname.includes("/epe/")) { + source = ESourceAuthorization["aura.moons"]; + } + await authorization(email, source); + dispatch( + actions.payment.update({ + activeSubPlan, + }) + ); + setIsAuth(true); + setTimeout(() => { + navigate(redirectUrl); + }, 1000); }; return ( @@ -220,9 +181,9 @@ function EmailEnterPage({ > {isLoading && } {!isLoading && - !(!apiError && !error && !isLoading && isAuth) && + !(!error?.length && !isLoading && isAuth) && t("_continue")} - {!apiError && !error && !isLoading && isAuth && ( + {!error?.length && !isLoading && isAuth && ( )} - {(error || apiError) && ( + {!!error?.length && ( Something went wrong )} - {apiError && ( - - )} ); } diff --git a/src/components/pages/TrialChoice/index.tsx b/src/components/pages/TrialChoice/index.tsx index 5e0b87c..7507f42 100755 --- a/src/components/pages/TrialChoice/index.tsx +++ b/src/components/pages/TrialChoice/index.tsx @@ -26,7 +26,7 @@ function TrialChoicePage() { const email = useSelector(selectors.selectEmail); const [subPlans, setSubPlans] = useState([]); const [isDisabled, setIsDisabled] = useState(true); - const allowedPlans = useMemo(() => ["stripe.37"], []); + const allowedPlans = useMemo(() => [""], []); useEffect(() => { (async () => { diff --git a/src/components/palmistry/step-email/step-email.tsx b/src/components/palmistry/step-email/step-email.tsx index 0a4cee3..86c397e 100644 --- a/src/components/palmistry/step-email/step-email.tsx +++ b/src/components/palmistry/step-email/step-email.tsx @@ -1,38 +1,27 @@ -import React from 'react'; +import React from "react"; import { useTranslation } from "react-i18next"; import { useDispatch } from "react-redux"; - -import { PatchPayload } from "@/api/resources/User"; -import { Step } from '@/hooks/palmistry/use-steps'; -import { useAuth } from "@/auth"; -import { useApi, ApiError, extractErrorMessage } from "@/api"; -import useSteps from '@/hooks/palmistry/use-steps'; -import Button from '@/components/palmistry/button/button'; -import Input from '@/components/palmistry/input/input'; -import { getClientTimezone } from "@/locales"; +import useSteps from "@/hooks/palmistry/use-steps"; +import Button from "@/components/palmistry/button/button"; +import Input from "@/components/palmistry/input/input"; import { actions } from "@/store"; import Title from "@/components/Title"; -import ErrorText from "@/components/ErrorText"; import Loader, { LoaderColor } from "@/components/Loader"; +import { useAuthentication } from "@/hooks/authentication/use-authentication"; +import { ESourceAuthorization } from "@/api/resources/User"; const emailRegex = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/; export default function StepEmail() { - const api = useApi(); - const { signUp } = useAuth(); - const { t, i18n } = useTranslation(); + const { t } = useTranslation(); const dispatch = useDispatch(); const steps = useSteps(); const [email, setEmail] = React.useState(steps.storedValue); const [emailIsValid, setEmailIsValid] = React.useState(false); - const [isLoading, setIsLoading] = React.useState(false); const [isAuth, setIsAuth] = React.useState(false); - const [apiError, setApiError] = React.useState(null); - const [error, setError] = React.useState(false); - const timezone = getClientTimezone(); - const locale = i18n.language; + const { error, isLoading, authorization } = useAuthentication(); const onChangeEmail = (value: string) => { setEmail(value); @@ -49,51 +38,16 @@ export default function StepEmail() { if (emailIsValid) { dispatch(actions.form.addEmail(email)); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [email]); - const authorization = async () => { - try { - setIsLoading(true); - const auth = await api.auth({ email, timezone, locale }); - const { auth: { token, user } } = auth; - - signUp(token, user); - const payload: PatchPayload = { - user: { - profile_attributes: { - birthday: steps.getStoredValue(Step.Birthdate), - gender: steps.getStoredValue(Step.Gender), - }, - }, - token, - }; - - const relationshipStatus = steps.getStoredValue(Step.RelationshipStatus); - if (relationshipStatus) { - payload.user.profile_attributes!.relationship_status = relationshipStatus; - } - - const updatedUser = await api.updateUser(payload).catch((error) => console.log("Error: ", error)); - - if (updatedUser?.user) dispatch(actions.user.update(updatedUser.user)); - - dispatch(actions.status.update("registred")); - - setIsLoading(false); - setIsAuth(true); - } catch (error) { - console.error(error); - if (error instanceof ApiError) { - setApiError(error as ApiError); - } else { - setError(true); - } - setIsLoading(false); - } + const authorize = async () => { + await authorization(email, ESourceAuthorization["aura.palmistry"]); + setIsAuth(true); }; const onNext = async () => { - await authorization(); + await authorize(); steps.saveCurrent(email); steps.goNext(); }; @@ -101,7 +55,9 @@ export default function StepEmail() { return ( <>
-

Enter your email to get your advanced Palmistry reading with AURA

+

+ Enter your email to get your advanced Palmistry reading with AURA +

- By clicking "Continue" below you agree to AURA{' '} - + By clicking "Continue" below you agree to AURA{" "} + EULA - {' '} - and{' '} - + {" "} + and{" "} + Privacy Policy . @@ -140,9 +104,11 @@ export default function StepEmail() { > {isLoading && } - {!isLoading && !(!apiError && !error && !isLoading && isAuth) && t("_continue")} + {!isLoading && + !(!error?.length && !isLoading && isAuth) && + t("_continue")} - {!apiError && !error && !isLoading && isAuth && ( + {!error?.length && !isLoading && isAuth && ( } - {(error || apiError) && ( + {error?.length && ( Something went wrong )} - - {apiError && ( - - )} ); } diff --git a/src/components/palmistry/step-gender/step-gender.tsx b/src/components/palmistry/step-gender/step-gender.tsx index fb5809e..00dafd1 100644 --- a/src/components/palmistry/step-gender/step-gender.tsx +++ b/src/components/palmistry/step-gender/step-gender.tsx @@ -1,10 +1,14 @@ -import Button from '../button/button'; -import useSteps, { GenderChoice } from '../../../hooks/palmistry/use-steps'; +import Button from "../button/button"; +import useSteps, { GenderChoice } from "../../../hooks/palmistry/use-steps"; +import { useDispatch } from "react-redux"; +import { actions } from "@/store"; export default function StepGender() { const steps = useSteps(); + const dispatch = useDispatch(); const onNext = (choice: GenderChoice) => { + dispatch(actions.questionnaire.update({ gender: choice })); steps.saveCurrent(choice); steps.goNext(choice); }; @@ -14,9 +18,10 @@ export default function StepGender() {

What’s your gender?

- In Palmistry, everyone is a blend of masculine and feminine, so it helps to know yours. + In Palmistry, everyone is a blend of masculine and feminine, so it helps + to know yours.

- +