@opexa/portal-components 0.0.290 → 0.0.292

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/client/hooks/useAuthenticateMutation.js +8 -3
  2. package/dist/client/hooks/useJackpotPayoutsQuery.js +1 -0
  3. package/dist/client/hooks/useJackpotsCountQuery.js +1 -0
  4. package/dist/client/hooks/useSignInMutation.js +8 -3
  5. package/dist/components/Banner/Banner.client.d.ts +12 -0
  6. package/dist/components/Banner/Banner.client.js +49 -0
  7. package/dist/components/Bonus/Bonus.client.js +3 -3
  8. package/dist/components/PortalProvider/PortalProvider.d.ts +3 -2
  9. package/dist/components/PortalProvider/PortalProvider.js +3 -4
  10. package/dist/components/PortalProvider/Providers.d.ts +5 -4
  11. package/dist/components/PortalProvider/Providers.js +3 -2
  12. package/dist/components/SignIn/MobileNumberSignIn.d.ts +1 -5
  13. package/dist/components/SignIn/MobileNumberSignIn.js +5 -23
  14. package/dist/components/SignIn/NameAndPasswordSignIn.d.ts +1 -5
  15. package/dist/components/SignIn/NameAndPasswordSignIn.js +6 -14
  16. package/dist/components/SignIn/SignIn.lazy.js +1 -1
  17. package/dist/components/SignIn/SignInForm.d.ts +1 -5
  18. package/dist/components/SignIn/SignInForm.js +2 -2
  19. package/dist/constants/EnvVar.d.ts +0 -2
  20. package/dist/constants/EnvVar.js +0 -11
  21. package/dist/handlers/postAuthenticate.js +5 -1
  22. package/dist/handlers/postSession.js +5 -1
  23. package/dist/services/graphqlRequest.js +1 -9
  24. package/dist/services/httpRequest.js +1 -9
  25. package/dist/styles/theme.css +3 -0
  26. package/dist/third-parties/FacebookPixel/FacebookPixel.d.ts +4 -0
  27. package/dist/third-parties/FacebookPixel/FacebookPixel.js +4 -0
  28. package/dist/third-parties/FacebookPixel/api.d.ts +0 -0
  29. package/dist/third-parties/FacebookPixel/api.js +1 -0
  30. package/dist/third-parties/FacebookPixel/index.d.ts +1 -0
  31. package/dist/third-parties/FacebookPixel/index.js +1 -0
  32. package/dist/third-parties/GoogleRecaptcha/GoogleRecaptcha.d.ts +4 -0
  33. package/dist/third-parties/GoogleRecaptcha/GoogleRecaptcha.js +4 -0
  34. package/dist/third-parties/GoogleRecaptcha/api.d.ts +0 -0
  35. package/dist/third-parties/GoogleRecaptcha/api.js +1 -0
  36. package/dist/third-parties/GoogleRecaptcha/index.d.ts +1 -0
  37. package/dist/third-parties/GoogleRecaptcha/index.js +1 -0
  38. package/dist/third-parties/index.d.ts +2 -0
  39. package/dist/third-parties/index.js +2 -0
  40. package/dist/ui/Badge/Badge.d.ts +12 -0
  41. package/dist/ui/Badge/badge.recipe.d.ts +3 -0
  42. package/dist/ui/Badge/badge.recipe.js +11 -0
  43. package/package.json +2 -1
  44. package/dist/client/utils/recaptcha.d.ts +0 -14
  45. package/dist/client/utils/recaptcha.js +0 -18
@@ -1,22 +1,27 @@
1
1
  import { useMutation } from '@tanstack/react-query';
2
+ import { useReCaptcha } from 'next-recaptcha-v3';
2
3
  import { RECAPTCHA_HEADER_KEY } from '../../constants/index.js';
3
4
  import { getQueryClient } from '../../utils/getQueryClient.js';
4
5
  import { getAuthenticateMutationKey } from '../../utils/mutationKeys.js';
5
6
  import { getSessionQueryKey } from '../../utils/queryKeys.js';
6
7
  import { authenticate } from '../services/authenticate.js';
7
8
  import { getSession } from '../services/getSession.js';
8
- import { ReCAPTCHAExecute, ReCAPTCHAReady } from '../utils/recaptcha.js';
9
9
  export const useAuthenticateMutation = (config) => {
10
10
  const queryClient = getQueryClient();
11
+ const recaptcha = useReCaptcha();
11
12
  return useMutation({
12
13
  ...config,
13
14
  mutationKey: getAuthenticateMutationKey(),
14
15
  mutationFn: async (input) => {
15
16
  const session = await getSession();
16
- await ReCAPTCHAReady();
17
+ const token = recaptcha.reCaptchaKey
18
+ ? await recaptcha.executeRecaptcha('submit')
19
+ : null;
17
20
  await authenticate(input, {
18
21
  headers: {
19
- [RECAPTCHA_HEADER_KEY]: await ReCAPTCHAExecute({ action: 'submit' }),
22
+ ...(token && {
23
+ [RECAPTCHA_HEADER_KEY]: token,
24
+ }),
20
25
  ...(session.domain && {
21
26
  Domain: session.domain,
22
27
  }),
@@ -6,6 +6,7 @@ export const useJackpotPayoutsQuery = (input, config) => {
6
6
  refetchOnMount: false,
7
7
  refetchOnReconnect: false,
8
8
  refetchOnWindowFocus: false,
9
+ refetchInterval: 3000, // 3 seconds
9
10
  ...config,
10
11
  queryKey: getJackpotPayoutsQueryKey(input),
11
12
  queryFn: ({ pageParam, signal }) => {
@@ -6,6 +6,7 @@ export const useJackpotsCountQuery = (input, config) => {
6
6
  refetchOnMount: false,
7
7
  refetchOnReconnect: false,
8
8
  refetchOnWindowFocus: false,
9
+ refetchInterval: 3000, // 3 seconds
9
10
  ...config,
10
11
  queryKey: getJackpotsCountQueryKey(input),
11
12
  queryFn: async ({ signal }) => {
@@ -1,22 +1,27 @@
1
1
  import { useMutation } from '@tanstack/react-query';
2
+ import { useReCaptcha } from 'next-recaptcha-v3';
2
3
  import { RECAPTCHA_HEADER_KEY } from '../../constants/index.js';
3
4
  import { getQueryClient } from '../../utils/getQueryClient.js';
4
5
  import { getSignInMutationKey } from '../../utils/mutationKeys.js';
5
6
  import { getSessionQueryKey } from '../../utils/queryKeys.js';
6
7
  import { getSession } from '../services/getSession.js';
7
8
  import { signIn } from '../services/signIn.js';
8
- import { ReCAPTCHAExecute, ReCAPTCHAReady } from '../utils/recaptcha.js';
9
9
  export const useSignInMutation = (config) => {
10
10
  const queryClient = getQueryClient();
11
+ const recaptcha = useReCaptcha();
11
12
  return useMutation({
12
13
  ...config,
13
14
  mutationKey: getSignInMutationKey(),
14
15
  mutationFn: async (input) => {
15
16
  const session = await getSession();
16
- await ReCAPTCHAReady();
17
+ const token = recaptcha.reCaptchaKey
18
+ ? await recaptcha.executeRecaptcha('submit')
19
+ : null;
17
20
  const authenticator = await signIn(input, {
18
21
  headers: {
19
- [RECAPTCHA_HEADER_KEY]: await ReCAPTCHAExecute({ action: 'submit' }),
22
+ ...(token && {
23
+ [RECAPTCHA_HEADER_KEY]: token,
24
+ }),
20
25
  ...(session.domain && {
21
26
  Domain: session.domain,
22
27
  }),
@@ -0,0 +1,12 @@
1
+ import type { ImageProps } from 'next/image';
2
+ export interface BannerEntry {
3
+ src: ImageProps['src'];
4
+ redirectUrl?: string;
5
+ }
6
+ export interface BannerProps {
7
+ banners: BannerEntry[];
8
+ imageWidth?: number | [mobile: number, desktop: number];
9
+ imageHeight?: number | [mobile: number, desktop: number];
10
+ className?: string;
11
+ }
12
+ export declare function Banner__client(props: BannerProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,49 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import emblaCarouselAutoplay from 'embla-carousel-autoplay';
4
+ import useEmblaCarousel, {} from 'embla-carousel-react';
5
+ import isMobile from 'is-mobile';
6
+ import Image from 'next/image';
7
+ import Link from 'next/link';
8
+ import { Fragment, useEffect, useState } from 'react';
9
+ import { twMerge } from 'tailwind-merge';
10
+ import { dataAttr } from '../../utils/dataAttr.js';
11
+ export function Banner__client(props) {
12
+ const [emblaRef, emblaApi] = useEmblaCarousel({
13
+ loop: true,
14
+ align: 'start',
15
+ }, [
16
+ emblaCarouselAutoplay({
17
+ playOnInit: true,
18
+ delay: 5000,
19
+ }),
20
+ ]);
21
+ const [currentIndex, setCurrentIndex] = useState(0);
22
+ useEffect(() => {
23
+ function handler(detail) {
24
+ setCurrentIndex(detail?.selectedScrollSnap() ?? 0);
25
+ }
26
+ emblaApi?.on('scroll', handler);
27
+ emblaApi?.on('init', handler);
28
+ return () => {
29
+ emblaApi?.on('init', handler);
30
+ emblaApi?.off('scroll', handler);
31
+ };
32
+ }, [emblaApi]);
33
+ const imageWidth = !props.imageWidth
34
+ ? [400, 1200]
35
+ : Array.isArray(props.imageWidth)
36
+ ? props.imageWidth
37
+ : [props.imageWidth, props.imageWidth];
38
+ const imageHeight = !props.imageHeight
39
+ ? [225, 300]
40
+ : Array.isArray(props.imageHeight)
41
+ ? props.imageHeight
42
+ : [props.imageHeight, props.imageHeight];
43
+ return (_jsxs("div", { className: twMerge('relative', props.className), children: [_jsx("div", { ref: emblaRef, className: "overflow-hidden", children: _jsx("div", { className: "flex gap-2", children: props.banners.map((banner, index) => {
44
+ const img = (_jsx(Image, { src: banner.src, alt: "", width: isMobile() ? imageWidth[0] : imageWidth[1], height: isMobile() ? imageHeight[0] : imageHeight[1], className: "block h-auto w-full", priority: index === 0 }));
45
+ return (_jsx(Fragment, { children: !banner.redirectUrl ? (_jsx("div", { className: "w-full shrink-0", children: img })) : (_jsx(Link, { href: banner.redirectUrl, className: "block w-full shrink-0", "aria-label": `Open ${banner.redirectUrl}`, children: img })) }, index));
46
+ }) }) }), _jsx("div", { className: "absolute bottom-lg left-1/2 flex w-fit -translate-x-1/2 gap-2", children: props.banners.map((_, index) => (_jsx("button", { type: "button", className: "ui-active:bg-brand-500 bg-gray-300 size-3 shrink-0 rounded-full border border-white transition-all duration-300 ui-active:w-9", onClick: () => {
47
+ emblaApi?.scrollTo(index);
48
+ }, "aria-label": `Go to slide ${index + 1}`, "data-active": dataAttr(index === currentIndex) }, index))) })] }));
49
+ }
@@ -26,9 +26,9 @@ export function Bonus__client(props) {
26
26
  return null;
27
27
  const turnoverRequirement = parseDecimal(bonus.turnoverRequirement, 0);
28
28
  const currentTurnoverRequirementContribution = parseDecimal(bonus.currentTurnoverRequirementContribution, 0);
29
- return (_jsxs("div", { className: props.className, children: [_jsxs(Link, { href: props.viewAllUrl ?? '/rewards', className: "text-button-tertiary-fg flex items-center gap-lg text-lg font-semibold", children: [_jsx(ChevronLeftIcon, { className: "size-6" }), "Back to Rewards"] }), _jsx("div", { className: "mt-3xl", children: bonus.promo.banner?.url ? (_jsx(Image, { src: bonus.promo.banner.url, alt: "", width: 1024, height: 600, unoptimized: true, priority: true, className: "h-auto w-full" })) : (_jsx(DefaultImage, {})) }), _jsxs(Badge.Root, { size: "lg", round: false, colorScheme: remainingTime.expired ? 'danger' : 'gray', className: "mt-xl lg:mt-6", children: [_jsx(Badge.Icon, { children: _jsx(StopWatchIcon, {}) }), _jsx(Badge.Label, { children: remainingTime.expired ? 'Expired' : remainingTime.toString() })] }), _jsx("h1", { className: "text-text-primary-900 mt-xl text-2xl font-semibold lg:mt-6 lg:text-3xl", children: bonus.promo.name }), _jsx("p", { className: "text-text-primary-brand mt-xl text-base lg:mt-6 lg:text-lg", children: "Complete the wagering before time runs out to convert your bonus balance into real money!" }), _jsxs("div", { className: "border-border-primary bg-bg-tertiary text-text-secondary-700 mt-xl flex items-center justify-between rounded-md border px-3.5 py-xl lg:mt-6", children: [_jsx("p", { children: "Your bonus balance" }), _jsx("p", { children: _jsx("span", { className: "text-text-primary-900", children: formatNumber(bonus.balance, {
29
+ return (_jsxs("div", { className: props.className, children: [_jsxs(Link, { href: props.viewAllUrl ?? '/rewards', className: "text-button-tertiary-fg flex items-center gap-lg text-lg font-semibold", children: [_jsx(ChevronLeftIcon, { className: "size-6" }), "Back to all Rewards"] }), _jsx("div", { className: "mt-3xl", children: bonus.promo.banner?.url ? (_jsx(Image, { src: bonus.promo.banner.url, alt: "", width: 1024, height: 600, unoptimized: true, priority: true, className: "h-auto w-full rounded-xl" })) : (_jsx(DefaultImage, {})) }), _jsxs(Badge.Root, { size: "lg", round: false, colorScheme: remainingTime.expired ? 'danger' : 'brand-dark', className: "mt-xl lg:mt-6", children: [_jsx(Badge.Icon, { children: _jsx(StopWatchIcon, {}) }), _jsx(Badge.Label, { children: remainingTime.expired ? 'Expired' : remainingTime.toString() })] }), _jsx("h1", { className: "text-text-primary-900 mt-xl text-2xl font-semibold lg:mt-6 lg:text-3xl", children: bonus.promo.name }), _jsx("p", { className: "text-text-primary-brand mt-xl text-base lg:mt-6 lg:text-lg", children: "Complete the wagering before time runs out to convert your bonus balance into real money!" }), _jsxs("div", { className: "border-border-primary bg-bg-tertiary text-text-secondary-700 mt-xl flex items-center justify-between rounded-md border px-3.5 py-xl lg:mt-6", children: [_jsx("p", { children: "Your bonus balance" }), _jsx("p", { children: _jsx("span", { className: "text-text-primary-900", children: formatNumber(bonus.balance, {
30
30
  currency: localeInfo.currency.code,
31
- }) }) })] }), _jsxs("div", { className: "border-border-primary bg-bg-tertiary text-text-secondary-700 mt-xl rounded-md border px-3.5 py-xl lg:mt-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { children: "Wagering" }), _jsxs("p", { children: [currentTurnoverRequirementContribution, "/", turnoverRequirement] })] }), _jsx(Progress.Root, { className: "mt-2", min: 0, max: turnoverRequirement, value: clamp(currentTurnoverRequirementContribution, 0, turnoverRequirement), children: _jsx(Progress.Track, { children: _jsx(Progress.Range, {}) }) })] }), _jsxs(Collapsible.Root, { className: "mt-xl lg:mt-6", children: [_jsxs(Collapsible.Trigger, { className: "text-button-tertiary-fg flex w-fit items-center justify-center gap-sm text-sm font-semibold lg:mx-auto", children: ["Game Provider Contribution", _jsx(Collapsible.Indicator, { asChild: true, children: _jsx(ChevronRightIcon, { className: "size-5" }) })] }), _jsx(Collapsible.Content, { className: "border-border-primary bg-bg-tertiary text-text-secondary-700 mt-xl space-y-1.5 rounded-md border px-3.5 py-xl lg:mt-6", children: Object.entries(bonus.promo
31
+ }) }) })] }), _jsxs("div", { className: "border-border-primary bg-bg-tertiary text-text-secondary-700 mt-xl rounded-md border px-3.5 py-xl lg:mt-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("p", { children: ["Wagering ", bonus.currentTurnoverRequirementContributionPercentage, "%"] }), _jsxs("p", { children: [currentTurnoverRequirementContribution, "/", turnoverRequirement] })] }), _jsx(Progress.Root, { className: "mt-2", min: 0, max: turnoverRequirement, value: clamp(currentTurnoverRequirementContribution, 0, turnoverRequirement), children: _jsx(Progress.Track, { children: _jsx(Progress.Range, {}) }) })] }), _jsxs(Collapsible.Root, { className: "mt-xl lg:mt-6", children: [_jsxs(Collapsible.Trigger, { className: "text-button-tertiary-fg flex items-center gap-sm text-sm font-semibold", children: ["Game Provider Contribution", _jsx(Collapsible.Indicator, { asChild: true, children: _jsx(ChevronRightIcon, { className: "size-5" }) })] }), _jsx(Collapsible.Content, { className: "border-border-primary bg-bg-tertiary text-text-secondary-700 mt-xl space-y-1.5 rounded-md border px-3.5 py-xl lg:mt-6", children: Object.entries(bonus.promo
32
32
  .turnoverRequirementContributionPercentagePerGameProvider ?? {}).map(([provider, valueAsString]) => {
33
33
  const value = parseDecimal(valueAsString, 0);
34
34
  return (_jsxs("div", { className: "flex items-center justify-between gap-md", children: [_jsx("p", { className: "w-[11.25rem] shrink-0", children: capitalize(provider, {
@@ -42,5 +42,5 @@ export function Bonus__client(props) {
42
42
  function DefaultImage() {
43
43
  return (_jsx("div", { style: {
44
44
  background: 'radial-gradient(75.21% 75.21% at 50% 50%, rgba(249, 163, 8, 0.3) 0%, rgba(0, 0, 0, 0) 100%), var(--color-bg-primary-alt)',
45
- }, className: "overflow-hidden rounded-xl", children: _jsx(Image, { src: piggyBank, alt: "", className: "mx-auto h-auto w-[50%] shrink-0", draggable: false, width: 1024, height: 1024, priority: true }) }));
45
+ }, className: "overflow-hidden rounded-xl", children: _jsx(Image, { src: piggyBank, alt: "", className: "mx-auto h-auto w-[50%] shrink-0 rounded-xl", draggable: false, width: 1024, height: 1024, priority: true }) }));
46
46
  }
@@ -1,5 +1,6 @@
1
1
  import { type ReactNode } from 'react';
2
- export interface PortalProviderProps {
2
+ import { type ProvidersProps } from './Providers';
3
+ export interface PortalProviderProps extends ProvidersProps {
3
4
  children: ReactNode;
4
5
  }
5
- export declare function PortalProvider({ children }: PortalProviderProps): Promise<import("react/jsx-runtime").JSX.Element>;
6
+ export declare function PortalProvider({ recaptchaSiteKey, children, }: PortalProviderProps): Promise<import("react/jsx-runtime").JSX.Element>;
@@ -1,8 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { dehydrate, HydrationBoundary } from '@tanstack/react-query';
3
- import Script from 'next/script';
4
3
  import { Suspense } from 'react';
5
- import { INTERNALS__REPORT_WEB_VITALS, RECAPTCHA_SITE_KEY, } from '../../constants/index.js';
4
+ import { INTERNALS__REPORT_WEB_VITALS } from '../../constants/index.js';
6
5
  import { prefetchAccountQuery } from '../../server/utils/prefetchAccountQuery.js';
7
6
  import { prefetchPlatformQuery } from '../../server/utils/prefetchPlatformQuery.js';
8
7
  import { prefetchSessionQuery } from '../../server/utils/prefetchSessionQuery.js';
@@ -13,7 +12,7 @@ import { Providers } from './Providers.js';
13
12
  import { SetupDomain } from './SetupDomain.js';
14
13
  import { Snackbar } from './Snackbar.js';
15
14
  import { WebVitals } from './WebVitals.js';
16
- export async function PortalProvider({ children }) {
15
+ export async function PortalProvider({ recaptchaSiteKey, children, }) {
17
16
  const queryClient = getQueryClient();
18
17
  await Promise.allSettled([
19
18
  prefetchPlatformQuery(),
@@ -21,5 +20,5 @@ export async function PortalProvider({ children }) {
21
20
  prefetchAccountQuery(),
22
21
  prefetchWalletQuery(),
23
22
  ]);
24
- return (_jsxs(_Fragment, { children: [INTERNALS__REPORT_WEB_VITALS && _jsx(WebVitals, {}), _jsx(Providers, { children: _jsxs(HydrationBoundary, { state: dehydrate(queryClient), children: [children, _jsx(Suspense, { fallback: null, children: _jsx(SetupDomain, {}) })] }) }), _jsx(Snackbar, {}), _jsx(Suspense, { fallback: null, children: _jsx(FeatureFlag, {}) }), RECAPTCHA_SITE_KEY && (_jsx(Script, { src: `https://www.google.com/recaptcha/api.js?render=${RECAPTCHA_SITE_KEY}` }))] }));
23
+ return (_jsxs(_Fragment, { children: [INTERNALS__REPORT_WEB_VITALS && _jsx(WebVitals, {}), _jsx(Providers, { recaptchaSiteKey: recaptchaSiteKey, children: _jsxs(HydrationBoundary, { state: dehydrate(queryClient), children: [children, _jsx(Suspense, { fallback: null, children: _jsx(SetupDomain, {}) })] }) }), _jsx(Snackbar, {}), _jsx(Suspense, { fallback: null, children: _jsx(FeatureFlag, {}) })] }));
25
24
  }
@@ -1,4 +1,5 @@
1
- import type { ReactNode } from 'react';
2
- export declare function Providers({ children }: {
3
- children: ReactNode;
4
- }): import("react/jsx-runtime").JSX.Element;
1
+ import type { PropsWithChildren } from 'react';
2
+ export interface ProvidersProps {
3
+ recaptchaSiteKey?: string;
4
+ }
5
+ export declare function Providers({ recaptchaSiteKey, children, }: PropsWithChildren<ProvidersProps>): import("react/jsx-runtime").JSX.Element;
@@ -1,8 +1,9 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { QueryClientProvider } from '@tanstack/react-query';
4
+ import { ReCaptchaProvider } from 'next-recaptcha-v3';
4
5
  import { getQueryClient } from '../../utils/getQueryClient.js';
5
- export function Providers({ children }) {
6
+ export function Providers({ recaptchaSiteKey, children, }) {
6
7
  const queryClient = getQueryClient();
7
- return (_jsx(QueryClientProvider, { client: queryClient, children: children }));
8
+ return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ReCaptchaProvider, { reCaptchaKey: recaptchaSiteKey, children: children }) }));
8
9
  }
@@ -1,5 +1 @@
1
- interface Props {
2
- siteName?: string;
3
- }
4
- export declare function MobileNumberSignIn(props: Props): import("react/jsx-runtime").JSX.Element;
5
- export {};
1
+ export declare function MobileNumberSignIn(): import("react/jsx-runtime").JSX.Element;
@@ -19,8 +19,7 @@ import { Checkbox } from '../../ui/Checkbox/index.js';
19
19
  import { Field } from '../../ui/Field/index.js';
20
20
  import { PinInput } from '../../ui/PinInput/index.js';
21
21
  import { useSignInContext, useSignInPropsContext } from './SignInContext.js';
22
- import { getFriendlyErrorMessage } from './utils.js';
23
- export function MobileNumberSignIn(props) {
22
+ export function MobileNumberSignIn() {
24
23
  const signInProps = useSignInPropsContext();
25
24
  const router = useRouter();
26
25
  const context = useSignInContext();
@@ -40,18 +39,9 @@ export function MobileNumberSignIn(props) {
40
39
  globalStore.kycReminder.setOpen(true);
41
40
  },
42
41
  onError: (err) => {
43
- const errorTitle = err.name === 'MEMBER_ACCOUNT_BLACKLISTED'
44
- ? 'Your Account is Blacklisted'
45
- : err.name === 'MEMBER_ACCOUNT_SUSPENDED'
46
- ? 'Your Account is Suspended'
47
- : 'Sign In Failed';
48
42
  toaster.error({
49
- title: errorTitle,
50
- description: getFriendlyErrorMessage(err.name, {
51
- siteName: props.siteName,
52
- accountName: step1Form.getValues('mobileNumber'),
53
- signInOptions: 'MOBILE_NUMBER',
54
- }),
43
+ title: 'Sign In Failed',
44
+ description: err.message,
55
45
  });
56
46
  },
57
47
  });
@@ -61,17 +51,9 @@ export function MobileNumberSignIn(props) {
61
51
  cooldown.start();
62
52
  },
63
53
  onError: (err) => {
64
- const errorTitle = err.name === 'MEMBER_ACCOUNT_BLACKLISTED'
65
- ? 'Your Account is Blacklisted'
66
- : err.name === 'MEMBER_ACCOUNT_SUSPENDED'
67
- ? 'Your Account is Suspended'
68
- : 'Sign In Failed';
69
54
  toaster.error({
70
- title: errorTitle,
71
- description: getFriendlyErrorMessage(err.name, {
72
- siteName: props.siteName,
73
- accountName: step1Form.getValues('mobileNumber'),
74
- }),
55
+ title: 'Sign In Failed',
56
+ description: err.message,
75
57
  });
76
58
  },
77
59
  });
@@ -1,5 +1 @@
1
- interface Props {
2
- siteName?: string;
3
- }
4
- export declare function NameAndPasswordSignIn(props: Props): import("react/jsx-runtime").JSX.Element;
5
- export {};
1
+ export declare function NameAndPasswordSignIn(): import("react/jsx-runtime").JSX.Element;
@@ -18,8 +18,7 @@ import { Checkbox } from '../../ui/Checkbox/index.js';
18
18
  import { Field } from '../../ui/Field/index.js';
19
19
  import { PasswordInput } from '../../ui/PasswordInput/index.js';
20
20
  import { useSignInContext, useSignInPropsContext } from './SignInContext.js';
21
- import { getFriendlyErrorMessage } from './utils.js';
22
- export function NameAndPasswordSignIn(props) {
21
+ export function NameAndPasswordSignIn() {
23
22
  const signInProps = useSignInPropsContext();
24
23
  const context = useSignInContext();
25
24
  const router = useRouter();
@@ -46,17 +45,9 @@ export function NameAndPasswordSignIn(props) {
46
45
  }
47
46
  },
48
47
  onError(err) {
49
- const errorTitle = err.name === 'MEMBER_ACCOUNT_BLACKLISTED'
50
- ? 'Your Account is Blacklisted'
51
- : err.name === 'MEMBER_ACCOUNT_SUSPENDED'
52
- ? 'Your Account is Suspended'
53
- : 'Sign In Failed';
54
48
  toaster.error({
55
- title: errorTitle,
56
- description: getFriendlyErrorMessage(err.name, {
57
- siteName: props.siteName,
58
- accountName: form.getValues('name'),
59
- }),
49
+ title: 'Sign In Failed',
50
+ description: err.message,
60
51
  });
61
52
  },
62
53
  });
@@ -69,9 +60,10 @@ export function NameAndPasswordSignIn(props) {
69
60
  context.setStep(0);
70
61
  form.reset();
71
62
  },
72
- onError() {
63
+ onError(error) {
73
64
  toaster.error({
74
- description: 'Incorrect secret answer',
65
+ title: 'Sign In Failed',
66
+ description: error.message,
75
67
  });
76
68
  },
77
69
  });
@@ -16,5 +16,5 @@ export function SignIn(props) {
16
16
  const signInStore = useGlobalStore(useShallow((ctx) => ctx.signIn));
17
17
  return (_jsx(SignInPropsProvider, { value: props, children: _jsx(SignInProvider, { value: signIn, children: _jsx(Dialog.Root, { open: signInStore.open, onOpenChange: (details) => {
18
18
  signInStore.setOpen(details.open);
19
- }, lazyMount: true, unmountOnExit: true, closeOnEscape: false, closeOnInteractOutside: false, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, {}), _jsx(Dialog.Positioner, { children: _jsxs(Dialog.Content, { className: twMerge('bg-bg-primary-alt mx-auto h-full w-full items-start overflow-y-auto p-3xl pb-4xl lg:h-auto lg:w-[400px] lg:rounded-xl', props.className), children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsx(Image, { src: props.logo, alt: "", width: 200, height: 100, className: "mx-auto h-7.5 w-auto", draggable: false }), _jsx(SignInForm, { siteName: props.siteName })] }) })] }) }) }) }));
19
+ }, lazyMount: true, unmountOnExit: true, closeOnEscape: false, closeOnInteractOutside: false, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, {}), _jsx(Dialog.Positioner, { children: _jsxs(Dialog.Content, { className: twMerge('bg-bg-primary-alt mx-auto h-full w-full items-start overflow-y-auto p-3xl pb-4xl lg:h-auto lg:w-[400px] lg:rounded-xl', props.className), children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsx(Image, { src: props.logo, alt: "", width: 200, height: 100, className: "mx-auto h-7.5 w-auto", draggable: false }), _jsx(SignInForm, {})] }) })] }) }) }) }));
20
20
  }
@@ -1,5 +1 @@
1
- interface Props {
2
- siteName?: string;
3
- }
4
- export declare function SignInForm(props: Props): import("react/jsx-runtime").JSX.Element;
5
- export {};
1
+ export declare function SignInForm(): import("react/jsx-runtime").JSX.Element;
@@ -4,7 +4,7 @@ import { MobileNumberSignIn } from './MobileNumberSignIn.js';
4
4
  import { NameAndPasswordSignIn } from './NameAndPasswordSignIn.js';
5
5
  import { useSignInContext } from './SignInContext.js';
6
6
  import { SignInMethod } from './SignInMethod.js';
7
- export function SignInForm(props) {
7
+ export function SignInForm() {
8
8
  const context = useSignInContext();
9
- return (_jsxs(_Fragment, { children: [context.step === 1 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "mt-xl text-center text-lg font-semibold", children: "Log in to your account" }), _jsx("p", { className: "text-text-secondary-700 mt-xs text-center text-sm", children: "Welcome back! Please enter your details." })] })), _jsx(SignInMethod, {}), context.type === 'MOBILE_NUMBER' && (_jsx(MobileNumberSignIn, { siteName: props.siteName })), context.type === 'NAME_AND_PASSWORD' && (_jsx(NameAndPasswordSignIn, { siteName: props.siteName }))] }));
9
+ return (_jsxs(_Fragment, { children: [context.step === 1 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "mt-xl text-center text-lg font-semibold", children: "Log in to your account" }), _jsx("p", { className: "text-text-secondary-700 mt-xs text-center text-sm", children: "Welcome back! Please enter your details." })] })), _jsx(SignInMethod, {}), context.type === 'MOBILE_NUMBER' && _jsx(MobileNumberSignIn, {}), context.type === 'NAME_AND_PASSWORD' && _jsx(NameAndPasswordSignIn, {})] }));
10
10
  }
@@ -2,6 +2,4 @@ export declare const SITE_ID: string;
2
2
  export declare const PLATFORM_ID: string;
3
3
  export declare const PLATFORM_CODE: string;
4
4
  export declare const ENVIRONMENT: "production" | "development";
5
- export declare const RECAPTCHA_SITE_KEY: string;
6
- export declare const BYPASS_RECAPTCHA: boolean;
7
5
  export declare const INTERNALS__REPORT_WEB_VITALS: boolean;
@@ -18,17 +18,6 @@ export const ENVIRONMENT = z
18
18
  .enum(['production', 'development'])
19
19
  .catch('development')
20
20
  .parse(process.env.NEXT_PUBLIC_ENVIRONMENT);
21
- export const RECAPTCHA_SITE_KEY = z
22
- .string()
23
- .optional()
24
- .default('')
25
- .catch('')
26
- .parse(process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY);
27
- export const BYPASS_RECAPTCHA = z
28
- .any()
29
- .transform(Boolean)
30
- .catch(false)
31
- .parse(process.env.NEXT_PUBLIC_BYPASS_RECAPTCHA);
32
21
  export const INTERNALS__REPORT_WEB_VITALS = z
33
22
  .any()
34
23
  .transform(Boolean)
@@ -11,6 +11,7 @@ const AuthenticateDefinition = z.object({
11
11
  export async function postAuthenticate(request) {
12
12
  const body = await request.json();
13
13
  const parsed = AuthenticateDefinition.safeParse(body);
14
+ const userAgent = request.headers.get('user-agent');
14
15
  if (!parsed.success) {
15
16
  return NextResponse.json({
16
17
  ok: false,
@@ -28,6 +29,9 @@ export async function postAuthenticate(request) {
28
29
  ...(domain && {
29
30
  [DOMAIN_HEADER_KEY]: domain,
30
31
  }),
32
+ ...(userAgent && {
33
+ 'User-Agent': userAgent,
34
+ }),
31
35
  },
32
36
  });
33
37
  const response = NextResponse.json({ ok: true }, { status: 201 });
@@ -44,7 +48,7 @@ export async function postAuthenticate(request) {
44
48
  catch (e) {
45
49
  return NextResponse.json({
46
50
  ok: false,
47
- message: 'Unauthorized',
51
+ message: e instanceof Error ? e.message : 'Unauthorized',
48
52
  __error: e,
49
53
  }, { status: 401 });
50
54
  }
@@ -30,6 +30,7 @@ const CreateSessionDefinition = z.union([
30
30
  export async function postSession(request) {
31
31
  const body = await request.json();
32
32
  const parsed = CreateSessionDefinition.safeParse(body);
33
+ const userAgent = request.headers.get('user-agent');
33
34
  if (!parsed.success) {
34
35
  return NextResponse.json({
35
36
  ok: false,
@@ -47,6 +48,9 @@ export async function postSession(request) {
47
48
  ...(domain && {
48
49
  [DOMAIN_HEADER_KEY]: domain,
49
50
  }),
51
+ ...(userAgent && {
52
+ 'User-Agent': userAgent,
53
+ }),
50
54
  },
51
55
  });
52
56
  if (res.authenticator) {
@@ -71,7 +75,7 @@ export async function postSession(request) {
71
75
  catch (e) {
72
76
  return NextResponse.json({
73
77
  ok: false,
74
- message: 'Unauthorized',
78
+ message: e instanceof Error ? e.message : 'Unauthorized',
75
79
  __error: e,
76
80
  }, { status: 401 });
77
81
  }
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { BYPASS_RECAPTCHA, ENVIRONMENT, PLATFORM_CODE, PLATFORM_ID, RECAPTCHA_HEADER_KEY, SITE_ID, TEST_PASS_HEADER_KEY, } from '../constants/index.js';
2
+ import { ENVIRONMENT, PLATFORM_CODE, PLATFORM_ID, SITE_ID } from '../constants/index.js';
3
3
  export async function graphqlRequest(url, query, variables, options) {
4
4
  const headers = new Headers();
5
5
  headers.set('Role', 'MEMBER');
@@ -12,10 +12,6 @@ export async function graphqlRequest(url, query, variables, options) {
12
12
  new Headers(options?.headers).forEach((value, key) => {
13
13
  headers.set(key, value);
14
14
  });
15
- if (BYPASS_RECAPTCHA) {
16
- headers.set(TEST_PASS_HEADER_KEY, '');
17
- headers.delete(RECAPTCHA_HEADER_KEY);
18
- }
19
15
  const info = getOperationInfo(query);
20
16
  const url_ = new URL(url);
21
17
  if (info) {
@@ -114,10 +110,6 @@ export async function graphqlUpload(url, query, variables, options) {
114
110
  headers.set('Platform-Code', PLATFORM_CODE);
115
111
  headers.set('Environment', ENVIRONMENT);
116
112
  headers.delete('Content-Type');
117
- if (BYPASS_RECAPTCHA) {
118
- headers.set(TEST_PASS_HEADER_KEY, '');
119
- headers.delete(RECAPTCHA_HEADER_KEY);
120
- }
121
113
  const body = createUploadBody(query, variables);
122
114
  const info = getOperationInfo(query);
123
115
  const url_ = new URL(url);
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { BYPASS_RECAPTCHA, ENVIRONMENT, PLATFORM_CODE, PLATFORM_ID, RECAPTCHA_HEADER_KEY, SITE_ID, TEST_PASS_HEADER_KEY, } from '../constants/index.js';
2
+ import { ENVIRONMENT, PLATFORM_CODE, PLATFORM_ID, SITE_ID } from '../constants/index.js';
3
3
  export async function httpRequest(url, opts = {}) {
4
4
  const headers = new Headers(opts.headers);
5
5
  headers.set('Role', 'MEMBER');
@@ -10,10 +10,6 @@ export async function httpRequest(url, opts = {}) {
10
10
  new Headers(opts.headers).forEach((value, key) => {
11
11
  headers.set(key, value);
12
12
  });
13
- if (BYPASS_RECAPTCHA) {
14
- headers.set(TEST_PASS_HEADER_KEY, '');
15
- headers.delete(RECAPTCHA_HEADER_KEY);
16
- }
17
13
  const res = await fetch(url, {
18
14
  ...opts,
19
15
  headers,
@@ -47,10 +43,6 @@ httpRequest.json = async (url, opts = {}) => {
47
43
  new Headers(opts.headers).forEach((value, key) => {
48
44
  headers.set(key, value);
49
45
  });
50
- if (BYPASS_RECAPTCHA) {
51
- headers.set(TEST_PASS_HEADER_KEY, '');
52
- headers.delete(RECAPTCHA_HEADER_KEY);
53
- }
54
46
  const response = await fetch(url, {
55
47
  ...opts,
56
48
  headers,
@@ -178,6 +178,7 @@
178
178
  --color-brand-300: #fde272;
179
179
  --color-brand-400: #fac515;
180
180
  --color-brand-500: #eaaa08;
181
+ --color-brand-700: #d5b86f;
181
182
  --color-brand-800: #22262f;
182
183
  --color-brand-950: #542c0d;
183
184
  --color-gray-300: #d0d5dd;
@@ -204,6 +205,7 @@
204
205
  --color-button-tertiary-fg: #fac515;
205
206
  --color-button-tertiary-error-fg: #fda29b;
206
207
 
208
+ --color-bg-brand-dark-solid: #351e13;
207
209
  --color-bg-brand-solid: #ca8504;
208
210
  --color-bg-primary: #0c0e12;
209
211
  --color-bg-primary-900: #0c0e12;
@@ -256,6 +258,7 @@
256
258
  --color-border-disabled: #373a41;
257
259
  --color-border-disabled-subtle: #22262f;
258
260
  --color-border-brand: #fac515;
261
+ --color-border-brand-dark: #6b4328;
259
262
  --color-border-brand-solid: #ca8504;
260
263
 
261
264
  --font-sans: var(--font-sans);
@@ -0,0 +1,4 @@
1
+ export interface FacebookPixelProps {
2
+ fbId: string;
3
+ }
4
+ export declare function FacebookPixel(props: FacebookPixelProps): null;
@@ -0,0 +1,4 @@
1
+ export function FacebookPixel(props) {
2
+ console.log(props);
3
+ return null;
4
+ }
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ export * from './FacebookPixel';
@@ -0,0 +1 @@
1
+ export * from './FacebookPixel.js';
@@ -0,0 +1,4 @@
1
+ export interface GoogleRecaptchaProps {
2
+ siteKey: string;
3
+ }
4
+ export declare function GoogleRecaptcha(props: GoogleRecaptchaProps): null;
@@ -0,0 +1,4 @@
1
+ export function GoogleRecaptcha(props) {
2
+ console.log(props);
3
+ return null;
4
+ }
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ export * from './GoogleRecaptcha';
@@ -0,0 +1 @@
1
+ export * from './GoogleRecaptcha.js';
@@ -0,0 +1,2 @@
1
+ export * from './FacebookPixel';
2
+ export * from './GoogleRecaptcha';
@@ -0,0 +1,2 @@
1
+ export * from './FacebookPixel/index.js';
2
+ export * from './GoogleRecaptcha/index.js';
@@ -23,6 +23,7 @@ export declare const Root: import("react").ComponentType<import("@ark-ui/react")
23
23
  colorScheme: {
24
24
  gray: {};
25
25
  brand: {};
26
+ 'brand-dark': {};
26
27
  danger: {};
27
28
  success: {};
28
29
  warning: {};
@@ -57,6 +58,7 @@ export declare const Root: import("react").ComponentType<import("@ark-ui/react")
57
58
  colorScheme: {
58
59
  gray: {};
59
60
  brand: {};
61
+ 'brand-dark': {};
60
62
  danger: {};
61
63
  success: {};
62
64
  warning: {};
@@ -91,6 +93,7 @@ export declare const Root: import("react").ComponentType<import("@ark-ui/react")
91
93
  colorScheme: {
92
94
  gray: {};
93
95
  brand: {};
96
+ 'brand-dark': {};
94
97
  danger: {};
95
98
  success: {};
96
99
  warning: {};
@@ -129,6 +132,7 @@ export declare const Label: import("react").ComponentType<import("@ark-ui/react"
129
132
  colorScheme: {
130
133
  gray: {};
131
134
  brand: {};
135
+ 'brand-dark': {};
132
136
  danger: {};
133
137
  success: {};
134
138
  warning: {};
@@ -163,6 +167,7 @@ export declare const Label: import("react").ComponentType<import("@ark-ui/react"
163
167
  colorScheme: {
164
168
  gray: {};
165
169
  brand: {};
170
+ 'brand-dark': {};
166
171
  danger: {};
167
172
  success: {};
168
173
  warning: {};
@@ -197,6 +202,7 @@ export declare const Label: import("react").ComponentType<import("@ark-ui/react"
197
202
  colorScheme: {
198
203
  gray: {};
199
204
  brand: {};
205
+ 'brand-dark': {};
200
206
  danger: {};
201
207
  success: {};
202
208
  warning: {};
@@ -235,6 +241,7 @@ export declare const Indicator: import("react").ComponentType<import("@ark-ui/re
235
241
  colorScheme: {
236
242
  gray: {};
237
243
  brand: {};
244
+ 'brand-dark': {};
238
245
  danger: {};
239
246
  success: {};
240
247
  warning: {};
@@ -269,6 +276,7 @@ export declare const Indicator: import("react").ComponentType<import("@ark-ui/re
269
276
  colorScheme: {
270
277
  gray: {};
271
278
  brand: {};
279
+ 'brand-dark': {};
272
280
  danger: {};
273
281
  success: {};
274
282
  warning: {};
@@ -303,6 +311,7 @@ export declare const Indicator: import("react").ComponentType<import("@ark-ui/re
303
311
  colorScheme: {
304
312
  gray: {};
305
313
  brand: {};
314
+ 'brand-dark': {};
306
315
  danger: {};
307
316
  success: {};
308
317
  warning: {};
@@ -341,6 +350,7 @@ export declare const Icon: import("react").ComponentType<import("@ark-ui/react")
341
350
  colorScheme: {
342
351
  gray: {};
343
352
  brand: {};
353
+ 'brand-dark': {};
344
354
  danger: {};
345
355
  success: {};
346
356
  warning: {};
@@ -375,6 +385,7 @@ export declare const Icon: import("react").ComponentType<import("@ark-ui/react")
375
385
  colorScheme: {
376
386
  gray: {};
377
387
  brand: {};
388
+ 'brand-dark': {};
378
389
  danger: {};
379
390
  success: {};
380
391
  warning: {};
@@ -409,6 +420,7 @@ export declare const Icon: import("react").ComponentType<import("@ark-ui/react")
409
420
  colorScheme: {
410
421
  gray: {};
411
422
  brand: {};
423
+ 'brand-dark': {};
412
424
  danger: {};
413
425
  success: {};
414
426
  warning: {};
@@ -19,6 +19,7 @@ export declare const badgeRecipe: import("tailwind-variants").TVReturnType<{
19
19
  colorScheme: {
20
20
  gray: {};
21
21
  brand: {};
22
+ 'brand-dark': {};
22
23
  danger: {};
23
24
  success: {};
24
25
  warning: {};
@@ -53,6 +54,7 @@ export declare const badgeRecipe: import("tailwind-variants").TVReturnType<{
53
54
  colorScheme: {
54
55
  gray: {};
55
56
  brand: {};
57
+ 'brand-dark': {};
56
58
  danger: {};
57
59
  success: {};
58
60
  warning: {};
@@ -87,6 +89,7 @@ export declare const badgeRecipe: import("tailwind-variants").TVReturnType<{
87
89
  colorScheme: {
88
90
  gray: {};
89
91
  brand: {};
92
+ 'brand-dark': {};
90
93
  danger: {};
91
94
  success: {};
92
95
  warning: {};
@@ -29,6 +29,7 @@ export const badgeRecipe = tv({
29
29
  colorScheme: {
30
30
  gray: {},
31
31
  brand: {},
32
+ 'brand-dark': {},
32
33
  danger: {},
33
34
  success: {},
34
35
  warning: {},
@@ -64,6 +65,16 @@ export const badgeRecipe = tv({
64
65
  icon: 'text-utility-brand-600',
65
66
  },
66
67
  },
68
+ {
69
+ variant: 'subtle',
70
+ colorScheme: 'brand-dark',
71
+ className: {
72
+ root: 'bg-bg-brand-dark-solid border-border-brand-dark border',
73
+ label: 'text-brand-700',
74
+ indicator: 'bg-utility-brand-500',
75
+ icon: 'text-brand-700',
76
+ },
77
+ },
67
78
  {
68
79
  variant: 'subtle',
69
80
  colorScheme: 'success',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.290",
3
+ "version": "0.0.292",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",
@@ -87,6 +87,7 @@
87
87
  "embla-carousel-react": "^8.6.0",
88
88
  "is-mobile": "^5.0.0",
89
89
  "lodash-es": "^4.17.21",
90
+ "next-recaptcha-v3": "^1.5.2",
90
91
  "tailwind-merge": "^3.3.1",
91
92
  "tailwind-variants": "^1.0.0",
92
93
  "tailwind-zag": "^1.0.2",
@@ -1,14 +0,0 @@
1
- export interface ReCAPTCHAExecuteOptions {
2
- action: 'submit' | (string & {});
3
- }
4
- export interface ReCAPTCHA {
5
- ready(callback: () => void): void;
6
- execute(siteKey: string, options: ReCAPTCHAExecuteOptions): Promise<string>;
7
- }
8
- export declare function ReCAPTCHAReady(): Promise<void>;
9
- export declare function ReCAPTCHAExecute(options: ReCAPTCHAExecuteOptions): Promise<string>;
10
- declare global {
11
- interface Window {
12
- grecaptcha: ReCAPTCHA;
13
- }
14
- }
@@ -1,18 +0,0 @@
1
- import { RECAPTCHA_SITE_KEY } from '../../constants/index.js';
2
- let loaded = false;
3
- export function ReCAPTCHAReady() {
4
- return new Promise((resolve) => {
5
- if (!loaded) {
6
- window.grecaptcha.ready(() => {
7
- loaded = true;
8
- resolve();
9
- });
10
- }
11
- else {
12
- resolve();
13
- }
14
- });
15
- }
16
- export async function ReCAPTCHAExecute(options) {
17
- return await window.grecaptcha.execute(RECAPTCHA_SITE_KEY, options);
18
- }