Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/components/Onboarding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useAuthActions } from '@convex-dev/auth/react';
import { Button } from '~/components/ui/button';

export function Onboarding() {
//
const { signIn } = useAuthActions();

const handleSignIn = () => {
console.log('signing in');
signIn('google', { redirectTo: location.href });
};

return (
<div className="flex flex-col gap-8 my-6 h-full p-4">
<div className="text-center space-y-4">
<Button onClick={handleSignIn} className="text-4xl font-bold tracking-tight">
Welcome to Meseeks
</Button>
</div>
<footer className="absolute bottom-4 text-sm text-muted-foreground flex gap-4">
<a
href="/static/privacy-policy.md"
className="hover:underline"
target="_blank"
rel="noopener noreferrer"
>
Privacy Policy
</a>
<span>•</span>
<a
href="https://github.com/igor9silva/meseeks"
className="hover:underline"
target="_blank"
rel="noopener noreferrer"
>
GitHub
</a>
</footer>
</div>
);
}
64 changes: 0 additions & 64 deletions src/components/subscribe/SubscribePage.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/subscribe/faq/CreditsFaq.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const CreditsFaq = {
advertised cost.
</p>
<p>
Pro subscribers get $10 worth of monthly <strong>credits that never expire</strong>.
Pro subscribers get $10 worth of <strong>credits that never expire</strong>, every month.
</p>
<p>
You can also top up as much credits as you need, with zero markup from us -{' '}
Expand Down
5 changes: 3 additions & 2 deletions src/components/subscribe/faq/FaqSection.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { type ReactNode } from 'react';
import { QuestionDialog } from '~/components/QuestionDialog';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '~/components/ui/accordion';

import { faqs } from './index';

export function FaqSection() {
export function FaqSection({ questionComponent }: { questionComponent?: ReactNode }) {
//
return (
<div className="w-full max-w-4xl mx-auto space-y-4 mt-2">
Expand All @@ -24,7 +25,7 @@ export function FaqSection() {

<div className="text-center flex flex-col items-center gap-1 pt-4">
<p className="text-muted-foreground">Still have questions? We're here to help!</p>
<QuestionDialog />
{questionComponent || <QuestionDialog />}
</div>
</div>
);
Expand Down
21 changes: 21 additions & 0 deletions src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Route as TopUpRouteImport } from './routes/top-up'
import { Route as SubscribeRouteImport } from './routes/subscribe'
import { Route as SkillsRouteImport } from './routes/skills'
import { Route as SchedulesRouteImport } from './routes/schedules'
import { Route as PricingRouteImport } from './routes/pricing'
import { Route as BalanceRouteImport } from './routes/balance'
import { Route as SplatRouteImport } from './routes/$'
import { Route as PolarRouteRouteImport } from './routes/polar/route'
Expand Down Expand Up @@ -43,6 +44,11 @@ const SchedulesRoute = SchedulesRouteImport.update({
path: '/schedules',
getParentRoute: () => rootRouteImport,
} as any)
const PricingRoute = PricingRouteImport.update({
id: '/pricing',
path: '/pricing',
getParentRoute: () => rootRouteImport,
} as any)
const BalanceRoute = BalanceRouteImport.update({
id: '/balance',
path: '/balance',
Expand Down Expand Up @@ -93,6 +99,7 @@ export interface FileRoutesByFullPath {
'/polar': typeof PolarRouteRouteWithChildren
'/$': typeof SplatRoute
'/balance': typeof BalanceRoute
'/pricing': typeof PricingRoute
'/schedules': typeof SchedulesRoute
'/skills': typeof SkillsRoute
'/subscribe': typeof SubscribeRoute
Expand All @@ -108,6 +115,7 @@ export interface FileRoutesByTo {
'/polar': typeof PolarRouteRouteWithChildren
'/$': typeof SplatRoute
'/balance': typeof BalanceRoute
'/pricing': typeof PricingRoute
'/schedules': typeof SchedulesRoute
'/skills': typeof SkillsRoute
'/subscribe': typeof SubscribeRoute
Expand All @@ -124,6 +132,7 @@ export interface FileRoutesById {
'/polar': typeof PolarRouteRouteWithChildren
'/$': typeof SplatRoute
'/balance': typeof BalanceRoute
'/pricing': typeof PricingRoute
'/schedules': typeof SchedulesRoute
'/skills': typeof SkillsRoute
'/subscribe': typeof SubscribeRoute
Expand All @@ -141,6 +150,7 @@ export interface FileRouteTypes {
| '/polar'
| '/$'
| '/balance'
| '/pricing'
| '/schedules'
| '/skills'
| '/subscribe'
Expand All @@ -156,6 +166,7 @@ export interface FileRouteTypes {
| '/polar'
| '/$'
| '/balance'
| '/pricing'
| '/schedules'
| '/skills'
| '/subscribe'
Expand All @@ -171,6 +182,7 @@ export interface FileRouteTypes {
| '/polar'
| '/$'
| '/balance'
| '/pricing'
| '/schedules'
| '/skills'
| '/subscribe'
Expand All @@ -187,6 +199,7 @@ export interface RootRouteChildren {
PolarRouteRoute: typeof PolarRouteRouteWithChildren
SplatRoute: typeof SplatRoute
BalanceRoute: typeof BalanceRoute
PricingRoute: typeof PricingRoute
SchedulesRoute: typeof SchedulesRoute
SkillsRoute: typeof SkillsRoute
SubscribeRoute: typeof SubscribeRoute
Expand Down Expand Up @@ -227,6 +240,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof SchedulesRouteImport
parentRoute: typeof rootRouteImport
}
'/pricing': {
id: '/pricing'
path: '/pricing'
fullPath: '/pricing'
preLoaderRoute: typeof PricingRouteImport
parentRoute: typeof rootRouteImport
}
'/balance': {
id: '/balance'
path: '/balance'
Expand Down Expand Up @@ -311,6 +331,7 @@ const rootRouteChildren: RootRouteChildren = {
PolarRouteRoute: PolarRouteRouteWithChildren,
SplatRoute: SplatRoute,
BalanceRoute: BalanceRoute,
PricingRoute: PricingRoute,
SchedulesRoute: SchedulesRoute,
SkillsRoute: SkillsRoute,
SubscribeRoute: SubscribeRoute,
Expand Down
49 changes: 17 additions & 32 deletions src/routes/__root.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useAuthActions } from '@convex-dev/auth/react';
import { QueryClient } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { HeadContent, Outlet, Scripts, createRootRouteWithContext } from '@tanstack/react-router';
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
import { HeadContent, Outlet, Scripts, createRootRouteWithContext, useRouter } from '@tanstack/react-router';
import { TanStackRouterDevtools } from '@tanstack/router-devtools';
import { Analytics } from '@vercel/analytics/react';
import { SpeedInsights } from '@vercel/speed-insights/react';
import { AuthLoading, Authenticated, Unauthenticated } from 'convex/react';
Expand All @@ -11,9 +10,9 @@ import { CommandMenuDialog } from '~/components/CommandMenu';
import { FeedbackDialog } from '~/components/FeedbackDialog';
import { Loading } from '~/components/Loading';
import { MainHeader } from '~/components/MainHeader';
import { Onboarding } from '~/components/Onboarding';
import { RotatingLoadingMessage } from '~/components/RotatingLoadingMessage';
import { ScheduleIterationDialog } from '~/components/ScheduleIterationDialog';
import { Button } from '~/components/ui/button';
import { Toaster } from '~/components/ui/sonner';
import { useCurrentUser } from '~/hooks/useCurrentUser';
import { FeedbackDialogProvider, useFeedbackDialog } from '~/hooks/useFeedbackDialog';
Expand Down Expand Up @@ -113,7 +112,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<Loading className="h-svh" />
</AuthLoading>
<Unauthenticated>
<AccessDenied />
<AccessDenied>{children}</AccessDenied>
</Unauthenticated>
<Authenticated>
<Main>{children}</Main>
Expand Down Expand Up @@ -167,34 +166,20 @@ function MainWithFeedback({ children }: { children: React.ReactNode }) {
);
}

function AccessDenied() {
function AccessDenied({ children }: { children: React.ReactNode }) {
//
const { signIn } = useAuthActions();

return (
<div className="h-screen w-full flex flex-col items-center justify-center gap-4">
<Button onClick={() => signIn('google', { redirectTo: location.href })}>Continue with Google</Button>
<footer className="absolute bottom-4 text-sm text-muted-foreground flex gap-4">
<a
href="/static/privacy-policy.md"
className="hover:underline"
target="_blank"
rel="noopener noreferrer"
>
Privacy Policy
</a>
<span>•</span>
<a
href="https://github.com/igor9silva/meseeks"
className="hover:underline"
target="_blank"
rel="noopener noreferrer"
>
GitHub
</a>
</footer>
</div>
);
const router = useRouter();
const currentPath = router.state.location.pathname;

if (currentPath === '/pricing') {
return (
<div className="h-svh overflow-auto">
<main className="flex-1 flex flex-col">{children}</main>
</div>
);
}

return <Onboarding />;
}

// TODO: on .webmanifest:
Expand Down
54 changes: 54 additions & 0 deletions src/routes/pricing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useAuthActions } from '@convex-dev/auth/react';
import { createFileRoute } from '@tanstack/react-router';
import { track } from '@vercel/analytics/react';
import { MessageCircle } from 'lucide-react';
import { FaqSection, FounderCard, ProCard } from '~/components/subscribe';
import { Button } from '~/components/ui/button';

export const Route = createFileRoute('/pricing')({
component: PricingPage,
});

function PricingPage() {
//
const { signIn } = useAuthActions();

const handleGetStarted = async (product: 'pro' | 'founder') => {
track('tap_get_started_pricing', { product });
signIn('google', { redirectTo: '/subscribe' });
};

const handleAskQuestion = () => {
track('tap_ask_question_pricing');
signIn('google', { redirectTo: '/subscribe' });
};

const questionButton = (
<Button variant="secondary" size="sm" onClick={handleAskQuestion}>
<MessageCircle className="w-4 h-4 mr-2" />
Ask a question
</Button>
);

return (
<div className="flex flex-col gap-8 my-6 h-full p-4">
<div className="text-center space-y-4">
<h1 className="text-4xl font-bold tracking-tight">Pricing</h1>
</div>

<div className="grid md:grid-cols-2 gap-8 max-w-4xl mx-auto">
<ProCard onSubscribe={handleGetStarted} />
<FounderCard onSubscribe={handleGetStarted} />
</div>

<FaqSection questionComponent={questionButton} />

<div className="text-center text-sm text-muted-foreground pb-4">
<p>
This is a <strong>research preview</strong>. Expect issues.
</p>
<p>© 2025 isPro. All rights reserved.</p>
</div>
</div>
);
}
Loading