chore: add @doist/todoist-ai

dependency to package.json
اول دفعة من التطوير
This commit is contained in:
Your Name
2026-04-03 00:28:00 +02:00
parent 314f847ece
commit efb6854741
31 changed files with 2693 additions and 91 deletions

View File

@@ -12,6 +12,7 @@ import {
FolderClock,
KeyRound,
LogOut,
PartyPopper,
ShieldCheck,
Sparkles,
Trash2,
@@ -94,6 +95,21 @@ export default function AccountPage() {
const login = useAuthStore((state) => state.login);
const register = useAuthStore((state) => state.register);
const logout = useAuthStore((state) => state.logout);
const isNewAccount = useAuthStore((state) => state.isNewAccount);
const clearNewAccount = useAuthStore((state) => state.clearNewAccount);
const credits = useAuthStore((state) => state.credits);
// Welcome celebration for new registrations
useEffect(() => {
if (isNewAccount && user) {
toast(t('account.welcomeTitle'), {
description: t('account.welcomeMessage'),
icon: <PartyPopper className="h-5 w-5 text-amber-500" />,
duration: 6000,
});
clearNewAccount();
}
}, [isNewAccount, user, t, clearNewAccount]);
const [mode, setMode] = useState<AuthMode>('login');
const [email, setEmail] = useState('');

View File

@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import SEOHead from '@/components/seo/SEOHead';
import { generateWebPage, getSiteOrigin } from '@/utils/seo';
import { Check, X, Zap, Crown, Loader2 } from 'lucide-react';
import { ArrowRight, Check, Coins, Crown, Loader2, Scale, X, Zap } from 'lucide-react';
import { useAuthStore } from '@/stores/authStore';
import SocialProofStrip from '@/components/shared/SocialProofStrip';
import { getApiClient } from '@/services/api';
@@ -88,6 +88,32 @@ export default function PricingPage() {
<p className="mx-auto max-w-2xl text-lg text-slate-600 dark:text-slate-400">
{t('pages.pricing.subtitle', 'Start free with all tools. Upgrade when you need more power.')}
</p>
<div className="mx-auto mt-6 max-w-3xl rounded-2xl border border-primary-200 bg-primary-50/80 p-5 text-start shadow-sm dark:border-primary-900/40 dark:bg-primary-900/20">
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<div className="flex gap-3">
<div className="mt-0.5 rounded-2xl bg-white p-2 text-primary-600 shadow-sm dark:bg-slate-900 dark:text-primary-300">
<Scale className="h-5 w-5" />
</div>
<div>
<h2 className="text-base font-semibold text-slate-900 dark:text-white">
{t('pages.pricing.transparencyTitle')}
</h2>
<p className="mt-1 text-sm leading-6 text-slate-600 dark:text-slate-300">
{t('pages.pricing.transparencyBody')}
</p>
</div>
</div>
<Link
to="/pricing-transparency"
className="inline-flex items-center gap-2 self-start rounded-xl bg-white px-4 py-2 text-sm font-semibold text-primary-700 transition-colors hover:bg-primary-100 dark:bg-slate-900 dark:text-primary-300 dark:hover:bg-slate-800"
>
<Coins className="h-4 w-4" />
{t('pages.pricing.transparencyAction')}
<ArrowRight className="h-4 w-4" />
</Link>
</div>
</div>
</div>
<div className="deferred-section mb-12">

View File

@@ -0,0 +1,216 @@
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import {
ArrowRight,
Coins,
Gauge,
Receipt,
Scale,
ShieldCheck,
Sparkles,
} from 'lucide-react';
import SEOHead from '@/components/seo/SEOHead';
import { generateWebPage, getSiteOrigin } from '@/utils/seo';
export default function PricingTransparencyPage() {
const { t } = useTranslation();
const siteOrigin = getSiteOrigin(typeof window !== 'undefined' ? window.location.origin : '');
return (
<>
<SEOHead
title={t('pages.pricingTransparency.metaTitle')}
description={t('pages.pricingTransparency.metaDescription')}
path="/pricing-transparency"
jsonLd={generateWebPage({
name: t('pages.pricingTransparency.metaTitle'),
description: t('pages.pricingTransparency.metaDescription'),
url: `${siteOrigin}/pricing-transparency`,
})}
/>
<div className="mx-auto max-w-5xl">
<section className="rounded-[2rem] border border-slate-200 bg-white p-8 shadow-sm dark:border-slate-700 dark:bg-slate-900/70 sm:p-10">
<span className="inline-flex items-center rounded-full bg-primary-100 px-3 py-1 text-xs font-semibold uppercase tracking-[0.18em] text-primary-700 dark:bg-primary-900/30 dark:text-primary-300">
{t('pages.pricingTransparency.badge')}
</span>
<h1 className="mt-5 max-w-3xl text-3xl font-extrabold tracking-tight text-slate-900 dark:text-white sm:text-4xl">
{t('pages.pricingTransparency.title')}
</h1>
<p className="mt-4 max-w-3xl text-base leading-7 text-slate-600 dark:text-slate-400 sm:text-lg">
{t('pages.pricingTransparency.subtitle')}
</p>
<div className="mt-8 grid gap-4 md:grid-cols-3">
<div className="rounded-2xl bg-slate-50 p-5 dark:bg-slate-800/70">
<Coins className="h-5 w-5 text-primary-600 dark:text-primary-400" />
<h2 className="mt-3 text-base font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.creditsTitle')}
</h2>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.creditsBody')}
</p>
</div>
<div className="rounded-2xl bg-slate-50 p-5 dark:bg-slate-800/70">
<Receipt className="h-5 w-5 text-primary-600 dark:text-primary-400" />
<h2 className="mt-3 text-base font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.quoteTitle')}
</h2>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.quoteBody')}
</p>
</div>
<div className="rounded-2xl bg-slate-50 p-5 dark:bg-slate-800/70">
<Scale className="h-5 w-5 text-primary-600 dark:text-primary-400" />
<h2 className="mt-3 text-base font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.fairnessTitle')}
</h2>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.fairnessBody')}
</p>
</div>
</div>
</section>
<section className="mt-10 grid gap-6 lg:grid-cols-[1.2fr_0.8fr]">
<div className="rounded-[2rem] border border-slate-200 bg-white p-8 shadow-sm dark:border-slate-700 dark:bg-slate-900/70">
<div className="flex items-center gap-3">
<Gauge className="h-6 w-6 text-primary-600 dark:text-primary-400" />
<h2 className="text-2xl font-bold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.howTitle')}
</h2>
</div>
<p className="mt-4 text-sm leading-7 text-slate-600 dark:text-slate-400 sm:text-base">
{t('pages.pricingTransparency.howBody')}
</p>
<div className="mt-8 grid gap-5 sm:grid-cols-2">
<div className="rounded-2xl border border-slate-200 p-5 dark:border-slate-700">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.fixedTitle')}
</h3>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.fixedBody')}
</p>
</div>
<div className="rounded-2xl border border-slate-200 p-5 dark:border-slate-700">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.dynamicTitle')}
</h3>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.dynamicBody')}
</p>
</div>
</div>
</div>
<div className="rounded-[2rem] border border-slate-200 bg-white p-8 shadow-sm dark:border-slate-700 dark:bg-slate-900/70">
<div className="flex items-center gap-3">
<ShieldCheck className="h-6 w-6 text-primary-600 dark:text-primary-400" />
<h2 className="text-2xl font-bold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.noteTitle')}
</h2>
</div>
<p className="mt-4 text-sm leading-7 text-slate-600 dark:text-slate-400 sm:text-base">
{t('pages.pricingTransparency.noteBody')}
</p>
<div className="mt-6 rounded-2xl bg-primary-50 p-4 dark:bg-primary-900/20">
<p className="text-sm leading-6 text-primary-800 dark:text-primary-200">
{t('pages.pricingTransparency.noOneToOneBody')}
</p>
</div>
</div>
</section>
<section className="mt-10 rounded-[2rem] border border-slate-200 bg-white p-8 shadow-sm dark:border-slate-700 dark:bg-slate-900/70">
<h2 className="text-2xl font-bold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.examplesTitle')}
</h2>
<div className="mt-6 grid gap-4 md:grid-cols-3">
<div className="rounded-2xl bg-slate-50 p-5 dark:bg-slate-800/70">
<h3 className="text-base font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.exampleLightTitle')}
</h3>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.exampleLightBody')}
</p>
</div>
<div className="rounded-2xl bg-slate-50 p-5 dark:bg-slate-800/70">
<h3 className="text-base font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.exampleHeavyTitle')}
</h3>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.exampleHeavyBody')}
</p>
</div>
<div className="rounded-2xl bg-slate-50 p-5 dark:bg-slate-800/70">
<h3 className="text-base font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.exampleAiTitle')}
</h3>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.exampleAiBody')}
</p>
</div>
</div>
</section>
<section className="mt-10 rounded-[2rem] border border-slate-200 bg-white p-8 shadow-sm dark:border-slate-700 dark:bg-slate-900/70">
<div className="flex items-center gap-3">
<Sparkles className="h-6 w-6 text-primary-600 dark:text-primary-400" />
<h2 className="text-2xl font-bold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.futureTitle')}
</h2>
</div>
<p className="mt-4 text-sm leading-7 text-slate-600 dark:text-slate-400 sm:text-base">
{t('pages.pricingTransparency.futureBody')}
</p>
<div className="mt-8 grid gap-4 md:grid-cols-3">
<div className="rounded-2xl border border-slate-200 p-5 dark:border-slate-700">
<h3 className="font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.faq1q')}
</h3>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.faq1a')}
</p>
</div>
<div className="rounded-2xl border border-slate-200 p-5 dark:border-slate-700">
<h3 className="font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.faq2q')}
</h3>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.faq2a')}
</p>
</div>
<div className="rounded-2xl border border-slate-200 p-5 dark:border-slate-700">
<h3 className="font-semibold text-slate-900 dark:text-white">
{t('pages.pricingTransparency.faq3q')}
</h3>
<p className="mt-2 text-sm leading-6 text-slate-600 dark:text-slate-400">
{t('pages.pricingTransparency.faq3a')}
</p>
</div>
</div>
<div className="mt-8 flex flex-col gap-3 sm:flex-row">
<Link
to="/pricing"
className="inline-flex items-center justify-center gap-2 rounded-xl bg-primary-600 px-5 py-3 text-sm font-semibold text-white transition-colors hover:bg-primary-700"
>
{t('pages.pricingTransparency.pricingCta')}
<ArrowRight className="h-4 w-4" />
</Link>
<Link
to="/tools"
className="inline-flex items-center justify-center rounded-xl border border-slate-300 px-5 py-3 text-sm font-semibold text-slate-700 transition-colors hover:bg-slate-50 dark:border-slate-600 dark:text-slate-200 dark:hover:bg-slate-800"
>
{t('pages.pricingTransparency.toolsCta')}
</Link>
</div>
</section>
</div>
</>
);
}