Preview
Full width desktop view
Code
pricing-2.tsx
1"use client";
2
3import React, { useState, useEffect } from "react";
4import { motion, AnimatePresence } from "framer-motion";
5import {
6 Lock,
7 Shield,
8 Crown,
9 Check,
10 X,
11 ChevronRight,
12 Star,
13 Zap,
14 Users,
15 FileText,
16 AlertCircle,
17 Loader2,
18 Eye,
19 EyeOff,
20} from "lucide-react";
21import { Button } from "@/components/ui/button";
22import { Card } from "@/components/ui/card";
23import { Badge } from "@/components/ui/badge";
24import { Alert, AlertDescription } from "@/components/ui/alert";
25import { Separator } from "@/components/ui/separator";
26import { Progress } from "@/components/ui/progress";
27
28interface User {
29 id: string;
30 name: string;
31 email: string;
32 isLoggedIn: boolean;
33 permissions: string[];
34 subscriptionTier: "free" | "premium" | "enterprise";
35}
36
37interface PricingTier {
38 id: string;
39 name: string;
40 price: number;
41 period: string;
42 features: string[];
43 popular?: boolean;
44 icon: React.ReactNode;
45}
46
47interface ConfidentialAccessSystemProps {
48 user?: User;
49 requiredPermission?: string;
50 contentTitle?: string;
51 contentDescription?: string;
52 onPurchase?: (tierId: string) => Promise<void>;
53 onLogin?: () => void;
54}
55
56const ConfidentialAccessSystem: React.FC<ConfidentialAccessSystemProps> = ({
57 user = {
58 id: "1",
59 name: "John Doe",
60 email: "john@example.com",
61 isLoggedIn: true,
62 permissions: ["basic"],
63 subscriptionTier: "free",
64 },
65 requiredPermission = "premium",
66 contentTitle = "Confidential Business Report",
67 contentDescription = "Access exclusive insights and strategic analysis reserved for premium members.",
68 onPurchase = async (tierId: string) => {
69 await new Promise((resolve) => setTimeout(resolve, 2000));
70 },
71 onLogin = () => console.log("Login triggered"),
72}) => {
73 const [currentView, setCurrentView] = useState<
74 "access-denied" | "upgrade-prompt" | "loading" | "error"
75 >("access-denied");
76 const [isLoading, setIsLoading] = useState(false);
77 const [selectedTier, setSelectedTier] = useState<string | null>(null);
78 const [showPreview, setShowPreview] = useState(false);
79 const [purchaseProgress, setPurchaseProgress] = useState(0);
80
81 const pricingTiers: PricingTier[] = [
82 {
83 id: "premium",
84 name: "Premium",
85 price: 29,
86 period: "month",
87 icon: <Crown className="h-6 w-6" />,
88 features: [
89 "Access to confidential reports",
90 "Advanced analytics dashboard",
91 "Priority customer support",
92 "Monthly strategy sessions",
93 "Export capabilities",
94 ],
95 },
96 {
97 id: "enterprise",
98 name: "Enterprise",
99 price: 99,
100 period: "month",
101 popular: true,
102 icon: <Shield className="h-6 w-6" />,
103 features: [
104 "Everything in Premium",
105 "Custom integrations",
106 "Dedicated account manager",
107 "Advanced security features",
108 "API access",
109 "White-label options",
110 ],
111 },
112 ];
113
114 const hasAccess =
115 user.isLoggedIn && user.permissions.includes(requiredPermission);
116
117 useEffect(() => {
118 if (!user.isLoggedIn) {
119 setCurrentView("access-denied");
120 } else if (!hasAccess) {
121 setCurrentView("upgrade-prompt");
122 }
123 }, [user, hasAccess]);
124
125 const handlePurchase = async (tierId: string) => {
126 alert(`Tier ID ${tierId}`);
127 };
128
129 const AccessDeniedView = () => (
130 <motion.div
131 initial={{ opacity: 0, y: 20 }}
132 animate={{ opacity: 1, y: 0 }}
133 exit={{ opacity: 0, y: -20 }}
134 className="min-h-screen bg-gradient-to-br from-background via-background to-muted/20 flex items-center justify-center p-4"
135 >
136 <Card className="w-full max-w-2xl p-8 text-center border-2 border-border/50 shadow-2xl">
137 <motion.div
138 initial={{ scale: 0 }}
139 animate={{ scale: 1 }}
140 transition={{ delay: 0.2, type: "spring", stiffness: 200 }}
141 className="mx-auto w-20 h-20 bg-destructive/10 rounded-full flex items-center justify-center mb-6"
142 >
143 <Lock className="h-10 w-10 text-destructive" />
144 </motion.div>
145
146 <motion.h1
147 initial={{ opacity: 0 }}
148 animate={{ opacity: 1 }}
149 transition={{ delay: 0.3 }}
150 className="text-3xl font-bold text-foreground mb-4"
151 >
152 {!user.isLoggedIn ? "Authentication Required" : "Access Restricted"}
153 </motion.h1>
154
155 <motion.p
156 initial={{ opacity: 0 }}
157 animate={{ opacity: 1 }}
158 transition={{ delay: 0.4 }}
159 className="text-muted-foreground text-lg mb-6"
160 >
161 {!user.isLoggedIn
162 ? "Please log in to view this confidential content."
163 : `This content requires ${requiredPermission} access level.`}
164 </motion.p>
165
166 <motion.div
167 initial={{ opacity: 0 }}
168 animate={{ opacity: 1 }}
169 transition={{ delay: 0.5 }}
170 className="bg-muted/30 rounded-lg p-6 mb-8"
171 >
172 <h3 className="font-semibold text-foreground mb-2">{contentTitle}</h3>
173 <p className="text-muted-foreground text-sm">{contentDescription}</p>
174
175 <div className="mt-4 flex items-center justify-center gap-2">
176 <Button
177 variant="ghost"
178 size="sm"
179 onClick={() => setShowPreview(!showPreview)}
180 className="text-muted-foreground hover:text-foreground"
181 >
182 {showPreview ? (
183 <EyeOff className="h-4 w-4 mr-2" />
184 ) : (
185 <Eye className="h-4 w-4 mr-2" />
186 )}
187 {showPreview ? "Hide Preview" : "Show Preview"}
188 </Button>
189 </div>
190
191 <AnimatePresence>
192 {showPreview && (
193 <motion.div
194 initial={{ opacity: 0, height: 0 }}
195 animate={{ opacity: 1, height: "auto" }}
196 exit={{ opacity: 0, height: 0 }}
197 className="mt-4 p-4 bg-background/50 rounded border border-border/50 relative overflow-hidden"
198 >
199 <div className="blur-sm">
200 <div className="h-4 bg-muted rounded mb-2"></div>
201 <div className="h-4 bg-muted rounded w-3/4 mb-2"></div>
202 <div className="h-4 bg-muted rounded w-1/2"></div>
203 </div>
204 <div className="absolute inset-0 flex items-center justify-center bg-background/80">
205 <Badge variant="secondary" className="font-medium">
206 <Lock className="h-3 w-3 mr-1" />
207 Premium Content
208 </Badge>
209 </div>
210 </motion.div>
211 )}
212 </AnimatePresence>
213 </motion.div>
214
215 <motion.div
216 initial={{ opacity: 0, y: 20 }}
217 animate={{ opacity: 1, y: 0 }}
218 transition={{ delay: 0.6 }}
219 className="flex flex-col sm:flex-row gap-4 justify-center"
220 >
221 {!user.isLoggedIn ? (
222 <Button onClick={onLogin} size="lg" className="group">
223 Sign In
224 <ChevronRight className="ml-2 h-4 w-4 group-hover:translate-x-1 transition-transform" />
225 </Button>
226 ) : (
227 <>
228 <Button
229 onClick={() => setCurrentView("upgrade-prompt")}
230 size="lg"
231 className="group"
232 >
233 <Crown className="mr-2 h-4 w-4" />
234 Upgrade Access
235 <ChevronRight className="ml-2 h-4 w-4 group-hover:translate-x-1 transition-transform" />
236 </Button>
237 <Button variant="outline" size="lg">
238 Contact Support
239 </Button>
240 </>
241 )}
242 </motion.div>
243
244 {user.isLoggedIn && (
245 <motion.div
246 initial={{ opacity: 0 }}
247 animate={{ opacity: 1 }}
248 transition={{ delay: 0.7 }}
249 className="mt-6 pt-6 border-t border-border/50"
250 >
251 <p className="text-sm text-muted-foreground">
252 Logged in as{" "}
253 <span className="font-medium text-foreground">{user.name}</span>
254 </p>
255 <Badge variant="outline" className="mt-2">
256 {user.subscriptionTier} plan
257 </Badge>
258 </motion.div>
259 )}
260 </Card>
261 </motion.div>
262 );
263
264 const UpgradePromptView = () => (
265 <motion.div
266 initial={{ opacity: 0 }}
267 animate={{ opacity: 1 }}
268 exit={{ opacity: 0 }}
269 className="min-h-screen bg-gradient-to-br from-background via-background to-primary/5 p-4"
270 >
271 <div className="max-w-6xl mx-auto py-12">
272 <motion.div
273 initial={{ opacity: 0, y: 20 }}
274 animate={{ opacity: 1, y: 0 }}
275 className="text-center mb-12"
276 >
277 <Badge variant="secondary" className="mb-4">
278 <Zap className="h-3 w-3 mr-1" />
279 Upgrade Required
280 </Badge>
281 <h1 className="text-4xl font-bold text-foreground mb-4">
282 Unlock Premium Content
283 </h1>
284 <p className="text-xl text-muted-foreground max-w-2xl mx-auto">
285 Get access to exclusive reports, advanced analytics, and premium
286 features
287 </p>
288 </motion.div>
289
290 <div className="grid md:grid-cols-2 gap-8 mb-12">
291 {pricingTiers.map((tier, index) => (
292 <motion.div
293 key={tier.id}
294 initial={{ opacity: 0, y: 20 }}
295 animate={{ opacity: 1, y: 0 }}
296 transition={{ delay: index * 0.1 }}
297 >
298 <Card
299 className={`relative p-8 h-full ${
300 tier.popular
301 ? "border-primary shadow-lg scale-105"
302 : "border-border"
303 }`}
304 >
305 {tier.popular && (
306 <Badge className="absolute -top-3 left-1/2 transform -translate-x-1/2">
307 <Star className="h-3 w-3 mr-1" />
308 Most Popular
309 </Badge>
310 )}
311
312 <div className="flex items-center gap-3 mb-6">
313 <div className="p-2 bg-primary/10 rounded-lg text-primary">
314 {tier.icon}
315 </div>
316 <div>
317 <h3 className="text-2xl font-bold text-foreground">
318 {tier.name}
319 </h3>
320 <div className="flex items-baseline gap-1">
321 <span className="text-3xl font-bold text-foreground">
322 ${tier.price}
323 </span>
324 <span className="text-muted-foreground">
325 /{tier.period}
326 </span>
327 </div>
328 </div>
329 </div>
330
331 <ul className="space-y-3 mb-8">
332 {tier.features.map((feature, featureIndex) => (
333 <li key={featureIndex} className="flex items-center gap-3">
334 <Check className="h-4 w-4 text-primary flex-shrink-0" />
335 <span className="text-muted-foreground">{feature}</span>
336 </li>
337 ))}
338 </ul>
339
340 <Button
341 onClick={() => handlePurchase(tier.id)}
342 disabled={isLoading}
343 className={`w-full ${
344 tier.popular ? "bg-primary hover:bg-primary/90" : ""
345 }`}
346 variant={tier.popular ? "default" : "outline"}
347 >
348 {isLoading && selectedTier === tier.id ? (
349 <Loader2 className="h-4 w-4 mr-2 animate-spin" />
350 ) : (
351 <Crown className="h-4 w-4 mr-2" />
352 )}
353 Choose {tier.name}
354 </Button>
355 </Card>
356 </motion.div>
357 ))}
358 </div>
359
360 <motion.div
361 initial={{ opacity: 0, y: 20 }}
362 animate={{ opacity: 1, y: 0 }}
363 transition={{ delay: 0.3 }}
364 className="text-center"
365 >
366 <Card className="p-6 bg-muted/30">
367 <div className="flex flex-col sm:flex-row items-center justify-center gap-6">
368 <div className="flex items-center gap-2 text-muted-foreground">
369 <Users className="h-5 w-5" />
370 <span>Trusted by 10,000+ professionals</span>
371 </div>
372 <Separator
373 orientation="vertical"
374 className="hidden sm:block h-6"
375 />
376 <div className="flex items-center gap-2 text-muted-foreground">
377 <Shield className="h-5 w-5" />
378 <span>Enterprise-grade security</span>
379 </div>
380 <Separator
381 orientation="vertical"
382 className="hidden sm:block h-6"
383 />
384 <div className="flex items-center gap-2 text-muted-foreground">
385 <FileText className="h-5 w-5" />
386 <span>Cancel anytime</span>
387 </div>
388 </div>
389 </Card>
390 </motion.div>
391
392 <motion.div
393 initial={{ opacity: 0 }}
394 animate={{ opacity: 1 }}
395 transition={{ delay: 0.4 }}
396 className="text-center mt-8"
397 >
398 <Button
399 variant="ghost"
400 onClick={() => setCurrentView("access-denied")}
401 className="text-muted-foreground hover:text-foreground"
402 >
403 ← Back to content
404 </Button>
405 </motion.div>
406 </div>
407 </motion.div>
408 );
409
410 const LoadingView = () => (
411 <motion.div
412 initial={{ opacity: 0 }}
413 animate={{ opacity: 1 }}
414 exit={{ opacity: 0 }}
415 className="min-h-screen bg-background flex items-center justify-center p-4"
416 >
417 <Card className="w-full max-w-md p-8 text-center">
418 <motion.div
419 animate={{ rotate: 360 }}
420 transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
421 className="mx-auto w-16 h-16 bg-primary/10 rounded-full flex items-center justify-center mb-6"
422 >
423 <Loader2 className="h-8 w-8 text-primary animate-spin" />
424 </motion.div>
425
426 <h2 className="text-2xl font-bold text-foreground mb-4">
427 Processing Your Upgrade
428 </h2>
429 <p className="text-muted-foreground mb-6">
430 Please wait while we activate your premium access...
431 </p>
432
433 <div className="space-y-4">
434 <Progress value={purchaseProgress} className="w-full" />
435 <p className="text-sm text-muted-foreground">
436 {purchaseProgress < 30 && "Verifying payment..."}
437 {purchaseProgress >= 30 &&
438 purchaseProgress < 60 &&
439 "Activating features..."}
440 {purchaseProgress >= 60 &&
441 purchaseProgress < 90 &&
442 "Setting up your account..."}
443 {purchaseProgress >= 90 && "Almost done!"}
444 </p>
445 </div>
446 </Card>
447 </motion.div>
448 );
449
450 const ErrorView = () => (
451 <motion.div
452 initial={{ opacity: 0, y: 20 }}
453 animate={{ opacity: 1, y: 0 }}
454 exit={{ opacity: 0, y: -20 }}
455 className="min-h-screen bg-background flex items-center justify-center p-4"
456 >
457 <Card className="w-full max-w-md p-8 text-center">
458 <motion.div
459 initial={{ scale: 0 }}
460 animate={{ scale: 1 }}
461 transition={{ type: "spring", stiffness: 200 }}
462 className="mx-auto w-16 h-16 bg-destructive/10 rounded-full flex items-center justify-center mb-6"
463 >
464 <X className="h-8 w-8 text-destructive" />
465 </motion.div>
466
467 <h2 className="text-2xl font-bold text-foreground mb-4">
468 Purchase Failed
469 </h2>
470 <p className="text-muted-foreground mb-6">
471 We encountered an issue processing your payment. Please try again.
472 </p>
473
474 <Alert className="mb-6">
475 <AlertCircle className="h-4 w-4" />
476 <AlertDescription>
477 If the problem persists, please contact our support team for
478 assistance.
479 </AlertDescription>
480 </Alert>
481
482 <div className="flex flex-col gap-3">
483 <Button onClick={() => setCurrentView("upgrade-prompt")}>
484 Try Again
485 </Button>
486 <Button
487 variant="outline"
488 onClick={() => setCurrentView("access-denied")}
489 >
490 Go Back
491 </Button>
492 </div>
493 </Card>
494 </motion.div>
495 );
496
497 return (
498 <div className="font-sans antialiased">
499 <AnimatePresence mode="wait">
500 {currentView === "access-denied" && <AccessDeniedView />}
501 {currentView === "upgrade-prompt" && <UpgradePromptView />}
502 {currentView === "loading" && <LoadingView />}
503 {currentView === "error" && <ErrorView />}
504 </AnimatePresence>
505 </div>
506 );
507};
508
509export default ConfidentialAccessSystem;
Dependencies
External Libraries
framer-motionlucide-reactreact
Shadcn/UI Components
alertbadgebuttoncardprogressseparator