pricing page and page speed test updated
This commit is contained in:
parent
eecffff110
commit
cad40a36d5
39
app/(defaults)/pricing/page.tsx
Normal file
39
app/(defaults)/pricing/page.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import ComponentsPricingTableToggle from '@/components/pricing-table/components-pricing-table-toggle';
|
||||||
|
import IconArrowLeft from '@/components/icon/icon-arrow-left';
|
||||||
|
import PanelCodeHighlight from '@/components/panel-code-highlight';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Pricing Table',
|
||||||
|
};
|
||||||
|
|
||||||
|
const PricingTable = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ul className="flex space-x-2 rtl:space-x-reverse">
|
||||||
|
<li>
|
||||||
|
<Link href="/" className="text-primary hover:underline">
|
||||||
|
Dashboard
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li className="before:content-['/'] ltr:before:mr-2 rtl:before:ml-2">
|
||||||
|
<span>Pricing Table</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div className="space-y-8 pt-5">
|
||||||
|
{/* Basic */}
|
||||||
|
|
||||||
|
|
||||||
|
{/* Toggle */}
|
||||||
|
<ComponentsPricingTableToggle />
|
||||||
|
|
||||||
|
{/* Animated */}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PricingTable;
|
||||||
268
app/(defaults)/testing/page.tsx
Normal file
268
app/(defaults)/testing/page.tsx
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
'use client';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import axios from 'axios';
|
||||||
|
import {
|
||||||
|
Treemap,
|
||||||
|
Tooltip as ReTooltip,
|
||||||
|
ResponsiveContainer
|
||||||
|
} from 'recharts';
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
const [url, setUrl] = useState('');
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [reports, setReports] = useState<any>(null);
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
const [activeTab, setActiveTab] = useState<'mobile' | 'desktop'>('mobile');
|
||||||
|
|
||||||
|
// --- Helper to parse estimated savings like "1.2 s" or "1200 ms" ---
|
||||||
|
function parseSavings(value: string): number {
|
||||||
|
if (!value) return 0;
|
||||||
|
const val = parseFloat(value);
|
||||||
|
if (value.toLowerCase().includes('ms')) return val;
|
||||||
|
if (value.toLowerCase().includes('s')) return val * 1000;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAudit = async () => {
|
||||||
|
if (!url) return setError('Enter a URL');
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
setError('');
|
||||||
|
setReports(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data } = await axios.post('https://api.crawlerx.co/api/lighthouse/audit', { url });
|
||||||
|
|
||||||
|
// normalize the results
|
||||||
|
const normalizedResults: any = {};
|
||||||
|
['mobile', 'desktop'].forEach((tab) => {
|
||||||
|
const tabData = data.results?.[tab] || {};
|
||||||
|
normalizedResults[tab] = {
|
||||||
|
report: {
|
||||||
|
scores: tabData.scores || {},
|
||||||
|
metrics: tabData.metrics || {},
|
||||||
|
opportunities: Array.isArray(tabData.opportunities) ? tabData.opportunities : [],
|
||||||
|
diagnostics: tabData.diagnostics || {},
|
||||||
|
screenshot: tabData.screenshot || '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setReports(normalizedResults);
|
||||||
|
setActiveTab('mobile');
|
||||||
|
} catch (err: any) {
|
||||||
|
setError(err.response?.data?.message || err.message || 'Error');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderScoreCircle = (score: number) => {
|
||||||
|
const color =
|
||||||
|
score >= 90 ? 'text-green-500 border-green-500' :
|
||||||
|
score >= 50 ? 'text-yellow-500 border-yellow-500' :
|
||||||
|
'text-red-500 border-red-500';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`w-20 h-20 flex items-center justify-center rounded-full border-4 ${color}`}>
|
||||||
|
<span className="text-lg font-bold">{score}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderMetrics = (metrics: any = {}) => (
|
||||||
|
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4 mb-6">
|
||||||
|
{Object.entries(metrics).map(([key, value]) => (
|
||||||
|
<div key={key} className="bg-white p-4 rounded-lg shadow text-center">
|
||||||
|
<p className="text-sm font-medium text-gray-600">
|
||||||
|
{key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase())}
|
||||||
|
</p>
|
||||||
|
<p className="mt-2 font-semibold text-gray-800">{value ?? '-'}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderOpportunities = (opportunities: any[] = []) => (
|
||||||
|
<div className="bg-white rounded-lg shadow p-4 mb-6">
|
||||||
|
<h3 className="text-lg font-semibold mb-4">Opportunities</h3>
|
||||||
|
{opportunities.length === 0 && <p className="text-gray-500">No suggestions available.</p>}
|
||||||
|
{opportunities.map((op, idx) => (
|
||||||
|
<div key={idx} className="mb-3 border-b last:border-b-0 pb-2">
|
||||||
|
<p className="font-medium">{op.title ?? '-'}</p>
|
||||||
|
<p className="text-gray-500 text-sm">{op.description ?? '-'}</p>
|
||||||
|
{op.estimatedSavings && (
|
||||||
|
<p className="text-xs text-blue-600">Estimated Savings: {op.estimatedSavings}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderTreeMap = (opportunities: any[] = []) => {
|
||||||
|
if (opportunities.length === 0) return null;
|
||||||
|
|
||||||
|
const data = opportunities.map(op => ({
|
||||||
|
name: op.title || 'Untitled',
|
||||||
|
size: parseSavings(op.estimatedSavings)
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white rounded-lg shadow p-4 mb-6">
|
||||||
|
<h3 className="text-lg font-semibold mb-4">Opportunities Tree Map</h3>
|
||||||
|
<div style={{ width: '100%', height: 400 }}>
|
||||||
|
<ResponsiveContainer>
|
||||||
|
<Treemap
|
||||||
|
data={data}
|
||||||
|
dataKey="size"
|
||||||
|
nameKey="name"
|
||||||
|
stroke="#fff"
|
||||||
|
fill="#3182ce"
|
||||||
|
>
|
||||||
|
<ReTooltip
|
||||||
|
content={({ payload }) => {
|
||||||
|
if (!payload || payload.length === 0) return null;
|
||||||
|
const item = payload[0].payload;
|
||||||
|
return (
|
||||||
|
<div className="bg-white text-gray-800 p-2 rounded shadow">
|
||||||
|
<p className="font-semibold">{item.name}</p>
|
||||||
|
<p>{item.size} ms estimated savings</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Treemap>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderDiagnostics = (diagnostics: any = {}) => {
|
||||||
|
const keys = Object.keys(diagnostics);
|
||||||
|
return (
|
||||||
|
<div className="bg-white rounded-lg shadow p-4 mb-6">
|
||||||
|
<h3 className="text-lg font-semibold mb-4">Diagnostics</h3>
|
||||||
|
{keys.length === 0 && <p className="text-gray-500">No diagnostics available.</p>}
|
||||||
|
<div className="divide-y divide-gray-200">
|
||||||
|
{keys.map((key) => (
|
||||||
|
<div key={key} className="py-3 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium text-gray-700">
|
||||||
|
{key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase())}
|
||||||
|
</p>
|
||||||
|
{key === 'http2' && (
|
||||||
|
<p className="text-xs text-gray-500">
|
||||||
|
All resources should be served via HTTP/2 for better performance.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className={`px-2 py-1 text-xs font-bold rounded ${
|
||||||
|
diagnostics[key] ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-600'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{diagnostics[key] ? 'Pass' : 'Fail'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentReport = reports?.[activeTab]?.report || {
|
||||||
|
scores: {},
|
||||||
|
metrics: {},
|
||||||
|
opportunities: [],
|
||||||
|
diagnostics: {},
|
||||||
|
screenshot: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex flex-col items-center p-4 sm:p-8">
|
||||||
|
<h1 className="text-2xl sm:text-3xl font-bold mb-6 text-gray-800 text-center">
|
||||||
|
Lighthouse PageSpeed Audit
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{/* Input */}
|
||||||
|
<div className="flex flex-col sm:flex-row gap-4 w-full max-w-xl mb-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={url}
|
||||||
|
onChange={(e) => setUrl(e.target.value)}
|
||||||
|
placeholder="Enter URL"
|
||||||
|
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={handleAudit}
|
||||||
|
disabled={loading}
|
||||||
|
className={`px-4 py-2 rounded-lg font-semibold text-white shadow-md transition ${
|
||||||
|
loading ? 'bg-gray-400 cursor-not-allowed' : 'bg-blue-600 hover:bg-blue-700'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{loading ? 'Auditing...' : 'Run Audit'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && <p className="text-red-500 mt-2 text-center">{error}</p>}
|
||||||
|
|
||||||
|
{reports && (
|
||||||
|
<div className="w-full max-w-6xl mt-8">
|
||||||
|
{/* Tabs */}
|
||||||
|
<div className="flex gap-4 mb-4">
|
||||||
|
<button
|
||||||
|
className={`px-4 py-2 rounded-t-lg font-semibold ${activeTab === 'mobile' ? 'bg-blue-600 text-white' : 'bg-gray-200'}`}
|
||||||
|
onClick={() => setActiveTab('mobile')}
|
||||||
|
>
|
||||||
|
Mobile
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`px-4 py-2 rounded-t-lg font-semibold ${activeTab === 'desktop' ? 'bg-green-600 text-white' : 'bg-gray-200'}`}
|
||||||
|
onClick={() => setActiveTab('desktop')}
|
||||||
|
>
|
||||||
|
Desktop
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Top Scores */}
|
||||||
|
<div className="flex flex-wrap gap-6 justify-center mb-6">
|
||||||
|
{['performance', 'accessibility', 'bestPractices', 'seo', 'pwa'].map((key) => {
|
||||||
|
const score = currentReport.scores?.[key];
|
||||||
|
if (score === undefined || score === null) return null;
|
||||||
|
return (
|
||||||
|
<div key={key} className="text-center">
|
||||||
|
<p className="text-sm font-medium">{key.charAt(0).toUpperCase() + key.slice(1)}</p>
|
||||||
|
{renderScoreCircle(score)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Metrics */}
|
||||||
|
{renderMetrics(currentReport.metrics)}
|
||||||
|
|
||||||
|
{/* Opportunities */}
|
||||||
|
{renderOpportunities(currentReport.opportunities)}
|
||||||
|
|
||||||
|
{/* Tree Map */}
|
||||||
|
{renderTreeMap(currentReport.opportunities)}
|
||||||
|
|
||||||
|
{/* Diagnostics */}
|
||||||
|
{renderDiagnostics(currentReport.diagnostics)}
|
||||||
|
|
||||||
|
{/* Screenshot */}
|
||||||
|
{currentReport.screenshot && (
|
||||||
|
<div className="flex justify-center mb-6">
|
||||||
|
<img
|
||||||
|
src={currentReport.screenshot}
|
||||||
|
alt={`${activeTab} screenshot`}
|
||||||
|
className="border shadow rounded max-w-full h-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -13,7 +13,7 @@ export default function ForgotPasswordForm() {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setMessage("");
|
setMessage("");
|
||||||
try {
|
try {
|
||||||
const res = await axios.post("http://localhost:3020/api/auth/forgot-password", { email });
|
const res = await axios.post("https://api.crawlerx.co/api/auth/forgot-password", { email });
|
||||||
setMessage("✅ We’ve emailed you a reset code / link. Enter it below.");
|
setMessage("✅ We’ve emailed you a reset code / link. Enter it below.");
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export default function ResetPasswordForm() {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setMessage("");
|
setMessage("");
|
||||||
try {
|
try {
|
||||||
await axios.post("http://localhost:3020/api/auth/reset-password", {
|
await axios.post("https://api.crawlerx.co/api/auth/reset-password", {
|
||||||
email,
|
email,
|
||||||
token, // ✅ use token from URL
|
token, // ✅ use token from URL
|
||||||
newPassword,
|
newPassword,
|
||||||
|
|||||||
21
components/highlight.tsx
Normal file
21
components/highlight.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import 'highlight.js/styles/monokai-sublime.css';
|
||||||
|
import hightlight from 'highlight.js';
|
||||||
|
import { PropsWithChildren, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
const CodeHighlight = ({ children }: PropsWithChildren) => {
|
||||||
|
const highlightElement = useRef<any>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (highlightElement?.current) {
|
||||||
|
hightlight.highlightElement(highlightElement.current.querySelector('pre'));
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={highlightElement} className="highlight-el">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CodeHighlight;
|
||||||
37
components/panel-code-highlight.tsx
Normal file
37
components/panel-code-highlight.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
'use client';
|
||||||
|
import CodeHighlight from './highlight';
|
||||||
|
import IconCode from '@/components/icon/icon-code';
|
||||||
|
import React, { useState, ReactNode } from 'react';
|
||||||
|
|
||||||
|
interface PanelCodeHighlightProps {
|
||||||
|
children: ReactNode;
|
||||||
|
title?: string;
|
||||||
|
codeHighlight?: string;
|
||||||
|
id?: string;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PanelCodeHighlight = ({ children, title, codeHighlight, id, className = '' }: PanelCodeHighlightProps) => {
|
||||||
|
const [toggleCode, setToggleCode] = useState(false);
|
||||||
|
return (
|
||||||
|
<div className={`panel ${className}`} id={id}>
|
||||||
|
<div className="mb-5 flex items-center justify-between">
|
||||||
|
<h5 className="text-lg font-semibold dark:text-white-light">{title}</h5>
|
||||||
|
<button type="button" className="font-semibold hover:text-gray-400 dark:text-gray-400 dark:hover:text-gray-600" onClick={() => setToggleCode(!toggleCode)}>
|
||||||
|
<span className="flex items-center">
|
||||||
|
<IconCode className="me-2" />
|
||||||
|
Code
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{children}
|
||||||
|
{toggleCode && (
|
||||||
|
<CodeHighlight>
|
||||||
|
<pre className="language-xml">{codeHighlight}</pre>
|
||||||
|
</CodeHighlight>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PanelCodeHighlight;
|
||||||
168
components/pricing-table/components-pricing-table-toggle.tsx
Normal file
168
components/pricing-table/components-pricing-table-toggle.tsx
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
'use client';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { loadStripe, Stripe } from '@stripe/stripe-js';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
interface Plan {
|
||||||
|
name: string;
|
||||||
|
desc: string;
|
||||||
|
monthly: number;
|
||||||
|
yearly: number;
|
||||||
|
features: string[];
|
||||||
|
btnStyle: string;
|
||||||
|
popular?: boolean;
|
||||||
|
planId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⚡ Lazy load Stripe to avoid undefined.match errors
|
||||||
|
let stripePromise: Promise<Stripe | null> | null = null;
|
||||||
|
const getStripe = () => {
|
||||||
|
if (!stripePromise) {
|
||||||
|
const key = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY;
|
||||||
|
if (!key) throw new Error('Stripe publishable key is not defined!');
|
||||||
|
stripePromise = loadStripe(key);
|
||||||
|
}
|
||||||
|
return stripePromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ComponentsPricingTableToggle: React.FC = () => {
|
||||||
|
const [yearlyPrice, setYearlyPrice] = useState(false);
|
||||||
|
|
||||||
|
const plans: Plan[] = [
|
||||||
|
{
|
||||||
|
name: 'Starter SEO Crawl',
|
||||||
|
desc: 'Perfect for small websites. Crawl up to 5,000 pages per month.',
|
||||||
|
monthly: 19,
|
||||||
|
yearly: 19 * 12 * 0.8,
|
||||||
|
features: ['5,000 Pages/Month', 'Basic Crawl Reports', 'Email Support'],
|
||||||
|
btnStyle: 'btn-dark',
|
||||||
|
planId: 'starter-seo-crawl',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Pro SEO Crawl',
|
||||||
|
desc: 'Best for medium websites. Crawl up to 50,000 pages per month.',
|
||||||
|
monthly: 49,
|
||||||
|
yearly: 49 * 12 * 0.8,
|
||||||
|
features: ['50,000 Pages/Month', 'Advanced Crawl Reports', 'Priority Support'],
|
||||||
|
btnStyle: 'btn-primary',
|
||||||
|
popular: true,
|
||||||
|
planId: 'pro-seo-crawl',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Enterprise SEO Crawl',
|
||||||
|
desc: 'For large-scale websites. Unlimited crawling and dedicated support.',
|
||||||
|
monthly: 199,
|
||||||
|
yearly: 199 * 12 * 0.8,
|
||||||
|
features: ['Unlimited Pages', 'Custom Integrations', 'Dedicated Account Manager'],
|
||||||
|
btnStyle: 'btn-dark',
|
||||||
|
planId: 'enterprise-seo-crawl',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 🔹 Stripe Checkout handler
|
||||||
|
const handleBuyNow = async (plan: Plan) => {
|
||||||
|
try {
|
||||||
|
const stripe = await getStripe();
|
||||||
|
if (!stripe) return;
|
||||||
|
|
||||||
|
// 🔹 Call backend API to create Checkout Session
|
||||||
|
const { data } = await axios.post(
|
||||||
|
'https://api.crawlerx.co/api/payment/create-intent',
|
||||||
|
{
|
||||||
|
planId: plan.planId,
|
||||||
|
price: yearlyPrice ? plan.yearly : plan.monthly,
|
||||||
|
billing: yearlyPrice ? 'yearly' : 'monthly',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data.sessionId) {
|
||||||
|
console.error('No sessionId returned from backend!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔹 Redirect to Stripe Checkout
|
||||||
|
const { error } = await stripe.redirectToCheckout({ sessionId: data.sessionId });
|
||||||
|
if (error) console.error('Stripe redirect error:', error.message);
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error('Error creating checkout session:', err.response?.data || err.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-5 panel">
|
||||||
|
<div className="mx-auto max-w-[320px] dark:text-white-dark md:max-w-[1140px]">
|
||||||
|
{/* Toggle */}
|
||||||
|
<div className="mt-5 flex justify-center space-x-4 text-center text-base font-semibold md:mt-10">
|
||||||
|
<span className={`${!yearlyPrice ? 'text-primary' : 'text-white-dark'}`}>Monthly</span>
|
||||||
|
<label className="relative h-6 w-12">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="custom_switch peer absolute top-0 z-10 h-full w-full cursor-pointer opacity-0"
|
||||||
|
onChange={() => setYearlyPrice(!yearlyPrice)}
|
||||||
|
/>
|
||||||
|
<span className="outline_checkbox bg-icon block h-full rounded-full border-2 border-[#ebedf2]
|
||||||
|
before:absolute before:bottom-1 before:h-4 before:w-4 before:rounded-full before:bg-[#ebedf2]
|
||||||
|
before:transition-all before:duration-300 peer-checked:border-primary peer-checked:before:bg-primary
|
||||||
|
ltr:before:left-1 ltr:peer-checked:before:left-7">
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<span className={`relative ${yearlyPrice ? 'text-primary' : ' text-white-dark'} `}>
|
||||||
|
Yearly
|
||||||
|
<span className="badge absolute my-auto hidden whitespace-nowrap rounded-full bg-success ltr:left-full ltr:ml-2">
|
||||||
|
20% Off
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Plans */}
|
||||||
|
<div className="mt-5 space-y-4 text-white-dark md:mt-16 md:flex md:space-y-0">
|
||||||
|
{plans.map((plan, idx) => (
|
||||||
|
<div
|
||||||
|
key={idx}
|
||||||
|
className="relative rounded-md border border-white-light p-4 transition-all duration-300
|
||||||
|
hover:shadow-[0_0_15px_1px_rgba(113,106,202,0.20)] dark:border-[#1b2e4b] lg:p-9"
|
||||||
|
>
|
||||||
|
{plan.popular && (
|
||||||
|
<div className="absolute inset-x-0 top-0 flex h-10 items-center justify-center rounded-t-md bg-primary text-base text-white md:-top-[30px]">
|
||||||
|
Most Popular
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<h3 className="mb-5 text-xl font-semibold text-black dark:text-white-light">{plan.name}</h3>
|
||||||
|
<p>{plan.desc}</p>
|
||||||
|
<div className="my-7 p-2.5 text-center text-lg">
|
||||||
|
<strong
|
||||||
|
className={`text-xl ${
|
||||||
|
plan.popular ? 'text-primary lg:text-4xl'
|
||||||
|
: 'text-[#3b3f5c] dark:text-white-light lg:text-3xl'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
${yearlyPrice ? plan.yearly.toFixed(0) : plan.monthly}
|
||||||
|
</strong>{' '}
|
||||||
|
/ {yearlyPrice ? 'yearly' : 'monthly'}
|
||||||
|
</div>
|
||||||
|
<div className="mb-6">
|
||||||
|
<strong className="mb-3 inline-block text-[15px] text-black dark:text-white-light">
|
||||||
|
{plan.name} Features
|
||||||
|
</strong>
|
||||||
|
<ul className="space-y-3">
|
||||||
|
{plan.features.map((f, i) => (
|
||||||
|
<li key={i}>{f}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`btn ${plan.btnStyle} w-full`}
|
||||||
|
onClick={() => handleBuyNow(plan)}
|
||||||
|
>
|
||||||
|
Buy Now
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ComponentsPricingTableToggle;
|
||||||
291
package-lock.json
generated
291
package-lock.json
generated
@ -11,6 +11,7 @@
|
|||||||
"@emotion/react": "^11.10.6",
|
"@emotion/react": "^11.10.6",
|
||||||
"@headlessui/react": "^2.1.2",
|
"@headlessui/react": "^2.1.2",
|
||||||
"@reduxjs/toolkit": "^2.2.7",
|
"@reduxjs/toolkit": "^2.2.7",
|
||||||
|
"@stripe/stripe-js": "^7.9.0",
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
"@types/node": "^22.4.0",
|
"@types/node": "^22.4.0",
|
||||||
"@types/react": "18.3.10",
|
"@types/react": "18.3.10",
|
||||||
@ -19,6 +20,7 @@
|
|||||||
"eslint": "8.57.0",
|
"eslint": "8.57.0",
|
||||||
"eslint-config-next": "14.2.13",
|
"eslint-config-next": "14.2.13",
|
||||||
"fast-xml-parser": "^5.2.5",
|
"fast-xml-parser": "^5.2.5",
|
||||||
|
"highlight.js": "^11.11.1",
|
||||||
"i18next": "^23.13.0",
|
"i18next": "^23.13.0",
|
||||||
"next": "14.2.13",
|
"next": "14.2.13",
|
||||||
"ni18n": "^1.0.5",
|
"ni18n": "^1.0.5",
|
||||||
@ -29,6 +31,7 @@
|
|||||||
"react-perfect-scrollbar": "^1.5.8",
|
"react-perfect-scrollbar": "^1.5.8",
|
||||||
"react-popper": "^2.3.0",
|
"react-popper": "^2.3.0",
|
||||||
"react-redux": "^9.1.2",
|
"react-redux": "^9.1.2",
|
||||||
|
"recharts": "^3.2.1",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"universal-cookie": "^7.2.0",
|
"universal-cookie": "^7.2.0",
|
||||||
"yup": "^1.4.0"
|
"yup": "^1.4.0"
|
||||||
@ -929,6 +932,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz",
|
||||||
"integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA=="
|
"integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@stripe/stripe-js": {
|
||||||
|
"version": "7.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-7.9.0.tgz",
|
||||||
|
"integrity": "sha512-ggs5k+/0FUJcIgNY08aZTqpBTtbExkJMYMLSMwyucrhtWexVOEY1KJmhBsxf+E/Q15f5rbwBpj+t0t2AW2oCsQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.16"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@swc/counter": {
|
"node_modules/@swc/counter": {
|
||||||
"version": "0.1.3",
|
"version": "0.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||||
@ -1011,6 +1023,69 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||||
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
|
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/d3-array": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-color": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-ease": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-interpolate": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/d3-color": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-path": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-scale": {
|
||||||
|
"version": "4.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
|
||||||
|
"integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/d3-time": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-shape": {
|
||||||
|
"version": "3.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
|
||||||
|
"integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/d3-path": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-time": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-timer": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
@ -2153,6 +2228,127 @@
|
|||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/d3-array": {
|
||||||
|
"version": "3.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
|
||||||
|
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"internmap": "1 - 2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-color": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-ease": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-format": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-interpolate": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-color": "1 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-path": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-scale": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "2.10.0 - 3",
|
||||||
|
"d3-format": "1 - 3",
|
||||||
|
"d3-interpolate": "1.2.0 - 3",
|
||||||
|
"d3-time": "2.1.1 - 3",
|
||||||
|
"d3-time-format": "2 - 4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-shape": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-path": "^3.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-time": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "2 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-time-format": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-time": "1 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-timer": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/damerau-levenshtein": {
|
"node_modules/damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||||
@ -2222,6 +2418,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/decimal.js-light": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/deep-equal": {
|
"node_modules/deep-equal": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
|
||||||
@ -2542,6 +2744,16 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-toolkit": {
|
||||||
|
"version": "1.39.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.39.10.tgz",
|
||||||
|
"integrity": "sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"workspaces": [
|
||||||
|
"docs",
|
||||||
|
"benchmarks"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/escalade": {
|
"node_modules/escalade": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||||
@ -3124,6 +3336,12 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eventemitter3": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fast-deep-equal": {
|
"node_modules/fast-deep-equal": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
@ -3613,6 +3831,15 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/highlight.js": {
|
||||||
|
"version": "11.11.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz",
|
||||||
|
"integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hoist-non-react-statics": {
|
"node_modules/hoist-non-react-statics": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||||
@ -3732,6 +3959,15 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/internmap": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-arguments": {
|
"node_modules/is-arguments": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||||
@ -5372,6 +5608,33 @@
|
|||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/recharts": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/recharts/-/recharts-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-0JKwHRiFZdmLq/6nmilxEZl3pqb4T+aKkOkOi/ZISRZwfBhVMgInxzlYU9D4KnCH3KINScLy68m/OvMXoYGZUw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@reduxjs/toolkit": "1.x.x || 2.x.x",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"decimal.js-light": "^2.5.1",
|
||||||
|
"es-toolkit": "^1.39.3",
|
||||||
|
"eventemitter3": "^5.0.1",
|
||||||
|
"immer": "^10.1.1",
|
||||||
|
"react-redux": "8.x.x || 9.x.x",
|
||||||
|
"reselect": "5.1.1",
|
||||||
|
"tiny-invariant": "^1.3.3",
|
||||||
|
"use-sync-external-store": "^1.2.2",
|
||||||
|
"victory-vendor": "^37.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/redux": {
|
"node_modules/redux": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||||
@ -6059,6 +6322,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
|
||||||
"integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
|
"integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/tiny-invariant": {
|
||||||
|
"version": "1.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
|
||||||
|
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/tippy.js": {
|
"node_modules/tippy.js": {
|
||||||
"version": "6.3.7",
|
"version": "6.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
|
||||||
@ -6312,6 +6581,28 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/victory-vendor": {
|
||||||
|
"version": "37.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz",
|
||||||
|
"integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==",
|
||||||
|
"license": "MIT AND ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/d3-array": "^3.0.3",
|
||||||
|
"@types/d3-ease": "^3.0.0",
|
||||||
|
"@types/d3-interpolate": "^3.0.1",
|
||||||
|
"@types/d3-scale": "^4.0.2",
|
||||||
|
"@types/d3-shape": "^3.1.0",
|
||||||
|
"@types/d3-time": "^3.0.0",
|
||||||
|
"@types/d3-timer": "^3.0.0",
|
||||||
|
"d3-array": "^3.1.6",
|
||||||
|
"d3-ease": "^3.0.1",
|
||||||
|
"d3-interpolate": "^3.0.1",
|
||||||
|
"d3-scale": "^4.0.2",
|
||||||
|
"d3-shape": "^3.1.0",
|
||||||
|
"d3-time": "^3.0.0",
|
||||||
|
"d3-timer": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/void-elements": {
|
"node_modules/void-elements": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
"@emotion/react": "^11.10.6",
|
"@emotion/react": "^11.10.6",
|
||||||
"@headlessui/react": "^2.1.2",
|
"@headlessui/react": "^2.1.2",
|
||||||
"@reduxjs/toolkit": "^2.2.7",
|
"@reduxjs/toolkit": "^2.2.7",
|
||||||
|
"@stripe/stripe-js": "^7.9.0",
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
"@types/node": "^22.4.0",
|
"@types/node": "^22.4.0",
|
||||||
"@types/react": "18.3.10",
|
"@types/react": "18.3.10",
|
||||||
@ -20,6 +21,7 @@
|
|||||||
"eslint": "8.57.0",
|
"eslint": "8.57.0",
|
||||||
"eslint-config-next": "14.2.13",
|
"eslint-config-next": "14.2.13",
|
||||||
"fast-xml-parser": "^5.2.5",
|
"fast-xml-parser": "^5.2.5",
|
||||||
|
"highlight.js": "^11.11.1",
|
||||||
"i18next": "^23.13.0",
|
"i18next": "^23.13.0",
|
||||||
"next": "14.2.13",
|
"next": "14.2.13",
|
||||||
"ni18n": "^1.0.5",
|
"ni18n": "^1.0.5",
|
||||||
@ -30,6 +32,7 @@
|
|||||||
"react-perfect-scrollbar": "^1.5.8",
|
"react-perfect-scrollbar": "^1.5.8",
|
||||||
"react-popper": "^2.3.0",
|
"react-popper": "^2.3.0",
|
||||||
"react-redux": "^9.1.2",
|
"react-redux": "^9.1.2",
|
||||||
|
"recharts": "^3.2.1",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"universal-cookie": "^7.2.0",
|
"universal-cookie": "^7.2.0",
|
||||||
"yup": "^1.4.0"
|
"yup": "^1.4.0"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user