feat: Add staging banner to dev/test environment
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Has been cancelled
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Has been cancelled
- Add StagingBanner component that displays on dev/staging/test domains - Shows warning that site is not production-ready - Automatically detects staging environment via hostname or env vars - Dismissible banner with smooth animations - Only shows on dev.dk0.dev or other test domains
This commit is contained in:
@@ -7,6 +7,7 @@ import { AnalyticsProvider } from "@/components/AnalyticsProvider";
|
||||
import { ClientOnly } from "./components/ClientOnly";
|
||||
import BackgroundBlobsClient from "./components/BackgroundBlobsClient";
|
||||
import ChatWidget from "./components/ChatWidget";
|
||||
import { StagingBanner } from "@/components/StagingBanner";
|
||||
|
||||
const inter = Inter({
|
||||
variable: "--font-inter",
|
||||
@@ -33,6 +34,7 @@ export default function RootLayout({
|
||||
<AnalyticsProvider>
|
||||
<ToastProvider>
|
||||
<ClientOnly>
|
||||
<StagingBanner />
|
||||
<BackgroundBlobsClient />
|
||||
</ClientOnly>
|
||||
<div className="relative z-10">{children}</div>
|
||||
|
||||
62
components/StagingBanner.tsx
Normal file
62
components/StagingBanner.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { AlertTriangle, X } from 'lucide-react';
|
||||
|
||||
export function StagingBanner() {
|
||||
const [isVisible, setIsVisible] = React.useState(true);
|
||||
const [isStaging, setIsStaging] = React.useState(false);
|
||||
|
||||
// Check if we're in staging/dev environment (client-side check)
|
||||
React.useEffect(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const hostname = window.location.hostname;
|
||||
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || '';
|
||||
|
||||
const staging =
|
||||
hostname.includes('dev') ||
|
||||
hostname.includes('staging') ||
|
||||
hostname.includes('test') ||
|
||||
baseUrl.includes('dev') ||
|
||||
baseUrl.includes('staging') ||
|
||||
baseUrl.includes('test');
|
||||
|
||||
setIsStaging(staging);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (!isStaging || !isVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ y: -100, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
exit={{ y: -100, opacity: 0 }}
|
||||
className="fixed top-0 left-0 right-0 z-50 bg-gradient-to-r from-yellow-500 via-orange-500 to-red-500 text-white shadow-lg"
|
||||
>
|
||||
<div className="container mx-auto px-4 py-2 md:py-3 flex items-center justify-between gap-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<AlertTriangle className="w-5 h-5 animate-pulse flex-shrink-0" />
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-bold text-sm md:text-base">
|
||||
🧪 TEST / DEVELOPMENT VERSION
|
||||
</p>
|
||||
<p className="text-xs md:text-sm text-white/90">
|
||||
This is a staging environment. Not production-ready. Data may be unstable.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setIsVisible(false)}
|
||||
className="p-1 hover:bg-white/20 rounded transition-colors"
|
||||
aria-label="Close banner"
|
||||
>
|
||||
<X className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user