This commit is contained in:
Carl-Gerhard Lindesvärd
2026-01-21 11:21:40 +01:00
parent a58761e8d7
commit 3fa1a5429e
28 changed files with 661 additions and 172 deletions

View File

@@ -1,8 +1,9 @@
import { FullPageEmptyState } from '@/components/full-page-empty-state';
import FullPageLoadingState from '@/components/full-page-loading-state';
import { LoginNavbar } from '@/components/login-navbar';
import { PublicPageCard } from '@/components/public-page-card';
import { Button, LinkButton } from '@/components/ui/button';
import { useTRPC } from '@/integrations/trpc/react';
import { emailCategories } from '@openpanel/constants';
import { useMutation } from '@tanstack/react-query';
import { createFileRoute, useSearch } from '@tanstack/react-router';
import { useState } from 'react';
import { z } from 'zod';
@@ -27,16 +28,18 @@ function RouteComponent() {
const [isSuccess, setIsSuccess] = useState(false);
const [error, setError] = useState<string | null>(null);
const unsubscribeMutation = trpc.email.unsubscribe.useMutation({
onSuccess: () => {
setIsSuccess(true);
setIsUnsubscribing(false);
},
onError: (err) => {
setError(err.message || 'Failed to unsubscribe');
setIsUnsubscribing(false);
},
});
const unsubscribeMutation = useMutation(
trpc.email.unsubscribe.mutationOptions({
onSuccess: () => {
setIsSuccess(true);
setIsUnsubscribing(false);
},
onError: (err) => {
setError(err.message || 'Failed to unsubscribe');
setIsUnsubscribing(false);
},
}),
);
const handleUnsubscribe = () => {
setIsUnsubscribing(true);
@@ -49,64 +52,38 @@ function RouteComponent() {
if (isSuccess) {
return (
<div className="min-h-screen flex flex-col">
<LoginNavbar />
<div className="flex-1 center-center px-4">
<div className="max-w-md w-full text-center space-y-4">
<div className="text-6xl mb-4"></div>
<h1 className="text-2xl font-bold">Unsubscribed</h1>
<p className="text-muted-foreground">
You've been unsubscribed from {categoryName} emails.
</p>
<p className="text-sm text-muted-foreground">
You won't receive any more {categoryName.toLowerCase()} emails from
us.
</p>
</div>
</div>
</div>
<PublicPageCard
title="Unsubscribed"
description={`You've been unsubscribed from ${categoryName} emails. You won't receive any more ${categoryName.toLowerCase()} emails from
us.`}
/>
);
}
return (
<div className="min-h-screen flex flex-col">
<LoginNavbar />
<div className="flex-1 center-center px-4">
<div className="max-w-md w-full space-y-6">
<div className="text-center space-y-2">
<h1 className="text-2xl font-bold">Unsubscribe</h1>
<p className="text-muted-foreground">
Unsubscribe from {categoryName} emails?
</p>
<p className="text-sm text-muted-foreground">
You'll stop receiving {categoryName.toLowerCase()} emails sent to{' '}
<span className="font-mono text-xs">{email}</span>
</p>
<PublicPageCard
title="Unsubscribe"
description={
<>
Unsubscribe from {categoryName} emails? You'll stop receiving{' '}
{categoryName.toLowerCase()} emails sent to&nbsp;
<span className="">{email}</span>
</>
}
>
<div className="col gap-3">
{error && (
<div className="bg-destructive/10 text-destructive px-4 py-3 rounded-md text-sm">
{error}
</div>
{error && (
<div className="bg-destructive/10 text-destructive px-4 py-3 rounded-md text-sm">
{error}
</div>
)}
<div className="space-y-3">
<button
onClick={handleUnsubscribe}
disabled={isUnsubscribing}
className="w-full bg-black text-white py-3 px-4 rounded-md font-medium hover:bg-black/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{isUnsubscribing ? 'Unsubscribing...' : 'Confirm Unsubscribe'}
</button>
<a
href="/"
className="block text-center text-sm text-muted-foreground hover:text-foreground transition-colors"
>
Cancel
</a>
</div>
</div>
)}
<Button onClick={handleUnsubscribe} disabled={isUnsubscribing}>
{isUnsubscribing ? 'Unsubscribing...' : 'Confirm Unsubscribe'}
</Button>
<LinkButton href="/" variant="ghost">
Cancel
</LinkButton>
</div>
</div>
</PublicPageCard>
);
}