@opexa/portal-components 0.1.24 → 0.1.25

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.
@@ -0,0 +1 @@
1
+ export declare function ResponsibleGamingLimits(props: any): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import dynamic from 'next/dynamic';
4
+ const Component = dynamic(() => import('./ResponsibleGamingLimitsForm.lazy.js').then((m) => m.ResponsibleGamingLimitsForm), {
5
+ ssr: false,
6
+ loading: () => null,
7
+ });
8
+ export function ResponsibleGamingLimits(props) {
9
+ return _jsx(Component, { ...props });
10
+ }
@@ -0,0 +1 @@
1
+ export declare function ResponsibleGamingLimits(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,117 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { Tabs } from '../../ui/Tabs/index.js';
4
+ import Link from 'next/link';
5
+ import { useCallback, useState } from 'react';
6
+ import { useForm } from 'react-hook-form';
7
+ import { twMerge } from 'tailwind-merge';
8
+ import { useShallow } from 'zustand/shallow';
9
+ import { BetDepositLimitModal } from '@opexa/portal-components/BetDepositLimit';
10
+ import { RefreshCcw01Icon } from '../../icons/RefreshCcw01Icon.js';
11
+ import { InfoCircleIcon } from '../../icons/InfoCircleIcon.js';
12
+ import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
13
+ import { Progress } from '../../ui/Progress/index.js';
14
+ import { Tooltip } from '../../ui/Tooltip/index.js';
15
+ import { Field } from '../../ui/Field/index.js';
16
+ import { Button } from '../../ui/Button/index.js';
17
+ const INITIAL_BET_LIMITS = [
18
+ {
19
+ period: 'daily',
20
+ label: 'Daily Bet Limit',
21
+ limit: 5000,
22
+ used: 3000,
23
+ resetsLabel: 'Resets daily',
24
+ active: true,
25
+ },
26
+ {
27
+ period: 'monthly',
28
+ label: 'Monthly Bet Limit',
29
+ limit: 50000,
30
+ used: 0,
31
+ resetsLabel: 'Resets May 30, 2026',
32
+ active: false,
33
+ },
34
+ ];
35
+ const INITIAL_DEPOSIT_LIMITS = [
36
+ {
37
+ period: 'daily',
38
+ label: 'Daily Deposit Limit',
39
+ limit: 10000,
40
+ used: 0,
41
+ resetsLabel: 'Resets daily',
42
+ active: false,
43
+ },
44
+ {
45
+ period: 'monthly',
46
+ label: 'Monthly Deposit Limit',
47
+ limit: 100000,
48
+ used: 0,
49
+ resetsLabel: 'Resets May 30, 2026',
50
+ active: false,
51
+ },
52
+ ];
53
+ function getNewLimitKey(tab, period) {
54
+ return `${tab}-${period}`;
55
+ }
56
+ function formatPeso(amount) {
57
+ return `₱${amount.toLocaleString('en-PH')}`;
58
+ }
59
+ function getUsedPercent(used, limit) {
60
+ if (limit === 0)
61
+ return 0;
62
+ return Math.min(Math.round((used / limit) * 100), 100);
63
+ }
64
+ function getProgressColor(pct) {
65
+ if (pct >= 80)
66
+ return 'bg-[#D92D20]';
67
+ if (pct >= 50)
68
+ return 'bg-[#F79009]';
69
+ return 'bg-[#FAC515]';
70
+ }
71
+ function tabToLimitType(tab) {
72
+ return tab === 'Bet' ? 'bet' : 'deposit';
73
+ }
74
+ export function ResponsibleGamingLimits() {
75
+ const openModal = useGlobalStore(useShallow((state) => state.betDepositLimit.openModal));
76
+ const form = useForm({
77
+ defaultValues: {},
78
+ });
79
+ const [activeTab, setActiveTab] = useState('Deposit');
80
+ const [betLimits, setBetLimits] = useState(INITIAL_BET_LIMITS);
81
+ const [depositLimits, setDepositLimits] = useState(INITIAL_DEPOSIT_LIMITS);
82
+ const limits = activeTab === 'Bet' ? betLimits : depositLimits;
83
+ const applyConfirmedLimit = useCallback(() => {
84
+ const { type, period, requestedLimit } = useGlobalStore.getState().betDepositLimit;
85
+ const updateLimits = (cards) => cards.map((card) => card.period === period ? { ...card, limit: requestedLimit } : card);
86
+ if (type === 'bet') {
87
+ setBetLimits(updateLimits);
88
+ }
89
+ else {
90
+ setDepositLimits(updateLimits);
91
+ }
92
+ }, []);
93
+ const saveLimit = useCallback((card, inputValue) => {
94
+ const key = getNewLimitKey(activeTab, card.period);
95
+ const parsed = parseFloat(String(inputValue).replace(/[^0-9.]/g, ''));
96
+ if (Number.isNaN(parsed) || parsed <= 0) {
97
+ return;
98
+ }
99
+ openModal(tabToLimitType(activeTab), card.period, card.limit, parsed);
100
+ form.setValue(key, '');
101
+ }, [activeTab, form, openModal]);
102
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "bg-bg-secondary m-5 mx-auto my-10 rounded-xl px-4 py-6 lg:px-8 lg:py-10", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h1", { className: "text-text-primary-brand text-3xl font-bold lg:block", children: "Responsible Gaming" }), _jsxs("p", { className: "text-text-disabled mt-1 text-sm", children: ["Set limits for your gaming activity, including how much you can bet or deposit.", _jsx("br", { className: "hidden sm:inline" }), "These limits help you stay within the boundaries you choose."] })] }), _jsxs("div", { className: "bg-bg-primary border-border-dark mb-6 flex flex-col items-start justify-between gap-3 rounded-xl border px-4 py-4 shadow-xs sm:flex-row sm:items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "text-text-primary-brand text-sm font-semibold", children: "Learn More About Responsible Gaming" }), _jsx("p", { className: "text-text-disabled mt-0.5 text-sm", children: "Find helpful tips, safety reminders, and support resources to help you stay informed and in control while playing." })] }), _jsx(Link, { href: "/responsible-gaming", className: twMerge('border-border-dark text-text-primary-brand inline-flex shrink-0 items-center justify-center gap-1.5 rounded-lg border px-4 py-2.5 text-sm font-semibold shadow-xs transition-colors'), children: "Visit Responsible Gaming" })] }), _jsx(Tabs.Root, { value: activeTab, onValueChange: (details) => setActiveTab(details.value), className: "mb-6 w-fit", children: _jsxs(Tabs.List, { children: [_jsx(Tabs.Trigger, { value: "Deposit", children: "Deposit" }), _jsx(Tabs.Trigger, { value: "Bet", children: "Bet" }), _jsx(Tabs.Indicator, {})] }) }), _jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: limits.map((card) => {
103
+ const pct = getUsedPercent(card.used, card.limit);
104
+ const key = getNewLimitKey(activeTab, card.period);
105
+ return (_jsxs("div", { className: "border-border-dark bg-bg-primary flex flex-col gap-4 rounded-xl border p-5 shadow-xs", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("span", { className: twMerge('inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-medium', card.active
106
+ ? 'border border-[#085D3A] bg-[#053321] text-[#75E0A7]'
107
+ : 'border border-[#912018] bg-[#55160c] text-[#FDA29B]'), children: [_jsx("span", { className: twMerge('size-1.5 rounded-full', card.active ? 'bg-[#17B26A]' : 'bg-[#F04438]') }), card.active ? 'Active' : 'Inactive'] }), _jsxs("span", { className: "inline-flex items-center gap-1 rounded-full border border-[#b0841f] bg-[#191304] px-2.5 py-1 text-xs font-medium text-[#e2aa28]", children: [_jsx(RefreshCcw01Icon, { className: "size-3" }), card.resetsLabel] })] }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-semibold text-text-primary-brand", children: card.label }), _jsx("p", { className: "mt-1 text-2xl font-bold text-button-primary-bg", children: formatPeso(card.limit) })] }), _jsxs("div", { children: [_jsxs("div", { className: "text-text-disabled flex items-center justify-between text-xs", children: [_jsxs("span", { children: [formatPeso(card.used), " used"] }), _jsxs("span", { children: [pct, "%"] })] }), _jsx(Progress.Root, { value: pct, max: 100, variant: "unstyled", className: "relative mt-1.5 h-2 w-full", children: _jsx(Progress.Track, { className: "bg-bg-dark h-2 w-full rounded-full", children: _jsx(Progress.Range, { className: twMerge('h-full rounded-full transition-all duration-700 ease-in-out', getProgressColor(pct)) }) }) }), _jsxs("p", { className: "text-text-disabled mt-1.5 text-xs", children: ["Remaining: ", formatPeso(card.limit - card.used)] })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-2 flex items-center gap-1 text-sm font-medium text-text-primary-brand", children: [_jsx("span", { children: "Set new limit" }), _jsxs(Tooltip.Root, { openDelay: 0, closeDelay: 100, children: [_jsx(Tooltip.Trigger, { type: "button", className: "inline-flex", "aria-label": "Limit change information", children: _jsx(InfoCircleIcon, { className: "size-4 text-text-disabled" }) }), _jsx(Tooltip.Positioner, { children: _jsxs(Tooltip.Content, { className: "max-w-64 rounded-lg bg-[#0C111D] px-2.5 py-2 text-xs font-medium text-text-primary-brand", children: [_jsx(Tooltip.Arrow, {}), "Enter a new limit amount. Limits can only be lowered immediately. Limit increases take 24 hours to apply."] }) })] })] }), _jsxs("form", { className: "flex w-full items-center gap-2", onSubmit: form.handleSubmit((values) => {
108
+ console.log({
109
+ component: 'ResponsibleGamingLimits',
110
+ activeTab,
111
+ card,
112
+ values,
113
+ });
114
+ saveLimit(card, values[key] ?? '');
115
+ }), children: [_jsxs(Field.Root, { className: "relative w-full", children: [_jsx("span", { className: "text-text-disabled absolute top-1/2 left-2 shrink-0 -translate-y-1/2 text-sm", children: "\u20B1" }), _jsx(Field.Input, { className: "pl-6", type: "number", min: 0, placeholder: "0", ...form.register(key) })] }), _jsx(Button, { size: "md", variant: "solid", colorScheme: "primary", type: "submit", className: "w-fit shrink-0", children: "Save" })] })] })] }, card.period));
116
+ }) })] }), _jsx(BetDepositLimitModal, { onConfirm: applyConfirmedLimit })] }));
117
+ }
@@ -0,0 +1 @@
1
+ export declare function ResponsibleGamingLimitsForm(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,117 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { Tabs } from '../../ui/Tabs/index.js';
4
+ import Link from 'next/link';
5
+ import { useCallback, useState } from 'react';
6
+ import { useForm } from 'react-hook-form';
7
+ import { twMerge } from 'tailwind-merge';
8
+ import { useShallow } from 'zustand/shallow';
9
+ import { BetDepositLimitModal, } from '../BetDepositLimit/index.js';
10
+ import { RefreshCcw01Icon } from '../../icons/RefreshCcw01Icon.js';
11
+ import { InfoCircleIcon } from '../../icons/InfoCircleIcon.js';
12
+ import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
13
+ import { Progress } from '../../ui/Progress/index.js';
14
+ import { Tooltip } from '../../ui/Tooltip/index.js';
15
+ import { Field } from '../../ui/Field/index.js';
16
+ import { Button } from '../../ui/Button/index.js';
17
+ const INITIAL_BET_LIMITS = [
18
+ {
19
+ period: 'daily',
20
+ label: 'Daily Bet Limit',
21
+ limit: 5000,
22
+ used: 3000,
23
+ resetsLabel: 'Resets daily',
24
+ active: true,
25
+ },
26
+ {
27
+ period: 'monthly',
28
+ label: 'Monthly Bet Limit',
29
+ limit: 50000,
30
+ used: 0,
31
+ resetsLabel: 'Resets May 30, 2026',
32
+ active: false,
33
+ },
34
+ ];
35
+ const INITIAL_DEPOSIT_LIMITS = [
36
+ {
37
+ period: 'daily',
38
+ label: 'Daily Deposit Limit',
39
+ limit: 10000,
40
+ used: 0,
41
+ resetsLabel: 'Resets daily',
42
+ active: false,
43
+ },
44
+ {
45
+ period: 'monthly',
46
+ label: 'Monthly Deposit Limit',
47
+ limit: 100000,
48
+ used: 0,
49
+ resetsLabel: 'Resets May 30, 2026',
50
+ active: false,
51
+ },
52
+ ];
53
+ function getNewLimitKey(tab, period) {
54
+ return `${tab}-${period}`;
55
+ }
56
+ function formatPeso(amount) {
57
+ return `₱${amount.toLocaleString('en-PH')}`;
58
+ }
59
+ function getUsedPercent(used, limit) {
60
+ if (limit === 0)
61
+ return 0;
62
+ return Math.min(Math.round((used / limit) * 100), 100);
63
+ }
64
+ function getProgressColor(pct) {
65
+ if (pct >= 80)
66
+ return 'bg-[#D92D20]';
67
+ if (pct >= 50)
68
+ return 'bg-[#F79009]';
69
+ return 'bg-[#FAC515]';
70
+ }
71
+ function tabToLimitType(tab) {
72
+ return tab === 'Bet' ? 'bet' : 'deposit';
73
+ }
74
+ export function ResponsibleGamingLimitsForm() {
75
+ const openModal = useGlobalStore(useShallow((state) => state.betDepositLimit.openModal));
76
+ const form = useForm({
77
+ defaultValues: {},
78
+ });
79
+ const [activeTab, setActiveTab] = useState('Deposit');
80
+ const [betLimits, setBetLimits] = useState(INITIAL_BET_LIMITS);
81
+ const [depositLimits, setDepositLimits] = useState(INITIAL_DEPOSIT_LIMITS);
82
+ const limits = activeTab === 'Bet' ? betLimits : depositLimits;
83
+ const applyConfirmedLimit = useCallback(() => {
84
+ const { type, period, requestedLimit } = useGlobalStore.getState().betDepositLimit;
85
+ const updateLimits = (cards) => cards.map((card) => card.period === period ? { ...card, limit: requestedLimit } : card);
86
+ if (type === 'bet') {
87
+ setBetLimits(updateLimits);
88
+ }
89
+ else {
90
+ setDepositLimits(updateLimits);
91
+ }
92
+ }, []);
93
+ const saveLimit = useCallback((card, inputValue) => {
94
+ const key = getNewLimitKey(activeTab, card.period);
95
+ const parsed = parseFloat(String(inputValue).replace(/[^0-9.]/g, ''));
96
+ if (Number.isNaN(parsed) || parsed <= 0) {
97
+ return;
98
+ }
99
+ openModal(tabToLimitType(activeTab), card.period, card.limit, parsed);
100
+ form.setValue(key, '');
101
+ }, [activeTab, form, openModal]);
102
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "bg-bg-secondary m-5 mx-auto my-10 rounded-xl px-4 py-6 lg:px-8 lg:py-10", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h1", { className: "text-text-primary-brand text-3xl font-bold lg:block", children: "Responsible Gaming" }), _jsxs("p", { className: "text-text-disabled mt-1 text-sm", children: ["Set limits for your gaming activity, including how much you can bet or deposit.", _jsx("br", { className: "hidden sm:inline" }), "These limits help you stay within the boundaries you choose."] })] }), _jsxs("div", { className: "bg-bg-primary border-border-dark mb-6 flex flex-col items-start justify-between gap-3 rounded-xl border px-4 py-4 shadow-xs sm:flex-row sm:items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "text-text-primary-brand text-sm font-semibold", children: "Learn More About Responsible Gaming" }), _jsx("p", { className: "text-text-disabled mt-0.5 text-sm", children: "Find helpful tips, safety reminders, and support resources to help you stay informed and in control while playing." })] }), _jsx(Link, { href: "/responsible-gaming", className: twMerge('border-border-dark text-text-primary-brand inline-flex shrink-0 items-center justify-center gap-1.5 rounded-lg border px-4 py-2.5 text-sm font-semibold shadow-xs transition-colors'), children: "Visit Responsible Gaming" })] }), _jsx(Tabs.Root, { value: activeTab, onValueChange: (details) => setActiveTab(details.value), className: "mb-6 w-fit", children: _jsxs(Tabs.List, { children: [_jsx(Tabs.Trigger, { value: "Deposit", children: "Deposit" }), _jsx(Tabs.Trigger, { value: "Bet", children: "Bet" }), _jsx(Tabs.Indicator, {})] }) }), _jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: limits.map((card) => {
103
+ const pct = getUsedPercent(card.used, card.limit);
104
+ const key = getNewLimitKey(activeTab, card.period);
105
+ return (_jsxs("div", { className: "border-border-dark bg-bg-primary flex flex-col gap-4 rounded-xl border p-5 shadow-xs", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("span", { className: twMerge('inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-medium', card.active
106
+ ? 'border border-[#085D3A] bg-[#053321] text-[#75E0A7]'
107
+ : 'border border-[#912018] bg-[#55160c] text-[#FDA29B]'), children: [_jsx("span", { className: twMerge('size-1.5 rounded-full', card.active ? 'bg-[#17B26A]' : 'bg-[#F04438]') }), card.active ? 'Active' : 'Inactive'] }), _jsxs("span", { className: "inline-flex items-center gap-1 rounded-full border border-[#b0841f] bg-[#191304] px-2.5 py-1 text-xs font-medium text-[#e2aa28]", children: [_jsx(RefreshCcw01Icon, { className: "size-3" }), card.resetsLabel] })] }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-semibold text-text-primary-brand", children: card.label }), _jsx("p", { className: "mt-1 text-2xl font-bold text-button-primary-bg", children: formatPeso(card.limit) })] }), _jsxs("div", { children: [_jsxs("div", { className: "text-text-disabled flex items-center justify-between text-xs", children: [_jsxs("span", { children: [formatPeso(card.used), " used"] }), _jsxs("span", { children: [pct, "%"] })] }), _jsx(Progress.Root, { value: pct, max: 100, variant: "unstyled", className: "relative mt-1.5 h-2 w-full", children: _jsx(Progress.Track, { className: "bg-bg-dark h-2 w-full rounded-full", children: _jsx(Progress.Range, { className: twMerge('h-full rounded-full transition-all duration-700 ease-in-out', getProgressColor(pct)) }) }) }), _jsxs("p", { className: "text-text-disabled mt-1.5 text-xs", children: ["Remaining: ", formatPeso(card.limit - card.used)] })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-2 flex items-center gap-1 text-sm font-medium text-text-primary-brand", children: [_jsx("span", { children: "Set new limit" }), _jsxs(Tooltip.Root, { openDelay: 0, closeDelay: 100, children: [_jsx(Tooltip.Trigger, { type: "button", className: "inline-flex", "aria-label": "Limit change information", children: _jsx(InfoCircleIcon, { className: "size-4 text-text-disabled" }) }), _jsx(Tooltip.Positioner, { children: _jsxs(Tooltip.Content, { className: "max-w-64 rounded-lg bg-[#0C111D] px-2.5 py-2 text-xs font-medium text-text-primary-brand", children: [_jsx(Tooltip.Arrow, {}), "Enter a new limit amount. Limits can only be lowered immediately. Limit increases take 24 hours to apply."] }) })] })] }), _jsxs("form", { className: "flex w-full items-center gap-2", onSubmit: form.handleSubmit((values) => {
108
+ console.log({
109
+ component: 'ResponsibleGamingLimits',
110
+ activeTab,
111
+ card,
112
+ values,
113
+ });
114
+ saveLimit(card, values[key] ?? '');
115
+ }), children: [_jsxs(Field.Root, { className: "relative w-full", children: [_jsx("span", { className: "text-text-disabled absolute top-1/2 left-2 shrink-0 -translate-y-1/2 text-sm", children: "\u20B1" }), _jsx(Field.Input, { className: "pl-6", type: "number", min: 0, placeholder: "0", ...form.register(key) })] }), _jsx(Button, { size: "md", variant: "solid", colorScheme: "primary", type: "submit", className: "w-fit shrink-0", children: "Save" })] })] })] }, card.period));
116
+ }) })] }), _jsx(BetDepositLimitModal, { onConfirm: applyConfirmedLimit })] }));
117
+ }
@@ -0,0 +1 @@
1
+ export * from "./ResponsibleGamingLimits";
@@ -0,0 +1 @@
1
+ export * from "./ResponsibleGamingLimits.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",