import React, { useMemo, useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import {
Warehouse,
Car,
Snowflake,
Shield,
Clock,
DoorOpen,
Tag,
MapPin,
Phone,
DollarSign,
Star,
ChevronRight,
} from "lucide-react";
// shadcn/ui
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
// ---------- Mock Data ----------
const UNITS = [
{
id: "u1",
size: "5' x 5'",
sqft: 25,
type: ["Interior"],
climate: true,
driveUp: false,
door: "Roll-up",
onlinePrice: 39,
inStorePrice: 49,
promo: "1st Month $1",
available: true,
parking: false,
},
{
id: "u2",
size: "5' x 10'",
sqft: 50,
type: ["Interior"],
climate: true,
driveUp: false,
door: "Roll-up",
onlinePrice: 59,
inStorePrice: 72,
promo: "50% Off 2 Months",
available: true,
parking: false,
},
{
id: "u3",
size: "10' x 10'",
sqft: 100,
type: ["Drive-up"],
climate: false,
driveUp: true,
door: "Roll-up",
onlinePrice: 99,
inStorePrice: 119,
promo: "Web Special",
available: false,
parking: false,
},
{
id: "u4",
size: "10' x 15'",
sqft: 150,
type: ["Drive-up"],
climate: false,
driveUp: true,
door: "Roll-up",
onlinePrice: 129,
inStorePrice: 149,
promo: "Free Lock",
available: true,
parking: false,
},
{
id: "u5",
size: "10' x 20'",
sqft: 200,
type: ["Interior"],
climate: true,
driveUp: false,
door: "Roll-up",
onlinePrice: 169,
inStorePrice: 189,
promo: "1st Month $1",
available: true,
parking: false,
},
{
id: "p1",
size: "10' x 20'",
sqft: 200,
type: ["Vehicle", "Uncovered"],
climate: false,
driveUp: true,
door: "None",
onlinePrice: 50,
inStorePrice: 63,
promo: "Online Only",
available: true,
parking: true,
},
{
id: "p2",
size: "12' x 35'",
sqft: 420,
type: ["RV", "Covered"],
climate: false,
driveUp: true,
door: "None",
onlinePrice: 129,
inStorePrice: 149,
promo: "Limited Spots",
available: false,
parking: true,
},
];
const SIZES = ["All sizes", "5' x 5'", "5' x 10'", "10' x 10'", "10' x 15'", "10' x 20'", "12' x 35'"];
const formatUSD = (n) => `$${n.toLocaleString(undefined, { maximumFractionDigits: 0 })}`;
export default function StorageMockup() {
const [activeTab, setActiveTab] = useState("units");
const [size, setSize] = useState("All sizes");
const [climateOnly, setClimateOnly] = useState(false);
const [driveUpOnly, setDriveUpOnly] = useState(false);
const [availableOnly, setAvailableOnly] = useState(true);
const [sort, setSort] = useState("price-asc");
const [zip, setZip] = useState("");
const filtered = useMemo(() => {
let list = UNITS.filter((u) => (activeTab === "parking" ? u.parking : !u.parking));
if (size !== "All sizes") list = list.filter((u) => u.size === size);
if (climateOnly) list = list.filter((u) => u.climate);
if (driveUpOnly) list = list.filter((u) => u.driveUp);
if (availableOnly) list = list.filter((u) => u.available);
list = [...list].sort((a, b) => {
if (sort === "price-asc") return a.onlinePrice - b.onlinePrice;
if (sort === "price-desc") return b.onlinePrice - a.onlinePrice;
return a.sqft - b.sqft;
});
return list;
}, [activeTab, size, climateOnly, driveUpOnly, availableOnly, sort]);
return (
{/* Specials Banner */}
Online Specials: $1 First Month · 50% Off 2 Months · Free Lock
Claim Offer
{/* Filters + Listings */}
Storage Units
Vehicle Parking
);
}
// ---------- Top Bar / Header ----------
function TopBar() {
return (
);
}
function Header({ zip, setZip }: { zip: string; setZip: (v: string) => void }) {
return (
Clean, Secure Self Storage
Month-to-month rentals, online specials, and friendly on-site staff. Climate controlled and drive-up units available.
24/7 Cameras
Extended Access
Climate Control
);
}
function HeroMock() {
return (
Quick Quote
Pick a size and see current web rates.
Size
5' x 5'
5' x 10'
10' x 10'
10' x 15'
10' x 20'
Check Availability
);
}
// ---------- Filters ----------
function FilterBar({
size,
setSize,
climateOnly,
setClimateOnly,
driveUpOnly,
setDriveUpOnly,
availableOnly,
setAvailableOnly,
sort,
setSort,
}: any) {
return (
Size
{SIZES.map((s) => (
{s}
))}
Sort
Price: Low → High
Price: High → Low
Size: Small → Large
);
}
// ---------- Unit Grid ----------
function UnitGrid({ items }: { items: any[] }) {
return (
{items.map((u) => (
))}
{items.length === 0 && (
No units match your filters.
)}
);
}
function UnitCard({ unit }: { unit: any }) {
const [open, setOpen] = useState(false);
return (
{unit.size}
{unit.parking ? "Vehicle / Parking" : unit.driveUp ? "Drive-up" : "Interior"} · {unit.door}
Web Rate
{formatUSD(unit.onlinePrice)}/mo
In-Store {formatUSD(unit.inStorePrice)}
{unit.climate && Climate }
{unit.driveUp && Drive-up }
{unit.type.map((t: string) => (
{t}
))}
{unit.promo && {unit.promo} }
Camera monitored
6am–10pm access
{unit.available ? "Available" : "Waitlist"}
Reserve
Reserve {unit.size}
Lock in the web rate today. No credit card required.
setOpen(false)} />
Hold for 7 Days
);
}
function ReserveForm({ unit, onComplete }: { unit: any; onComplete: () => void }) {
const [submitting, setSubmitting] = useState(false);
const [done, setDone] = useState(false);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setSubmitting(true);
setTimeout(() => {
setSubmitting(false);
setDone(true);
setTimeout(onComplete, 1000);
}, 800);
};
return (
);
}
// ---------- Size Guide ----------
function SizeGuide() {
const items = [
{ size: "5' x 5'", text: "Closet – Boxes, small items", icon: },
{ size: "5' x 10'", text: "Walk-in closet – Studio apt.", icon: },
{ size: "10' x 10'", text: "One-bedroom home", icon: },
{ size: "10' x 15'", text: "Two-bedroom home", icon: },
{ size: "10' x 20'", text: "Whole home / vehicle", icon: },
];
return (
{items.map((it) => (
{it.icon}
))}
);
}
function BoxSVG() {
return (
);
}
// ---------- Features ----------
function Features() {
const feats = [
{ icon: , title: "24/7 Cameras", text: "Monitored facility with gated access." },
{ icon: , title: "Extended Hours", text: "Access 6am–10pm every day." },
{ icon: , title: "Climate Control", text: "Protects against heat & humidity." },
{ icon: , title: "Drive-Up", text: "Ground-floor convenience." },
{ icon: , title: "RV / Boat Parking", text: "Covered & uncovered options." },
{ icon: , title: "Flexible Terms", text: "Month-to-month leases." },
];
return (
Why Store With Us
{feats.map((f) => (
{f.icon}
))}
);
}
// ---------- Location & Hours ----------
function LocationHours() {
return (
4500 W Highway 40, Ocala, FL
Office Hours
Mon–Sat: 9am–6pm
Sun: 9am–5pm
Access Hours
Daily: 6am–10pm
);
}
// ---------- Testimonials ----------
function Testimonials() {
const items = [
{ name: "Avery", text: "Super clean and easy online reservation. Staff was helpful on move-in day.", stars: 5 },
{ name: "Jordan", text: "Love the climate units. My furniture stayed in perfect shape.", stars: 5 },
{ name: "Taylor", text: "Great rates and the gated access feels safe.", stars: 4 },
];
return (
{items.map((r, i) => (
{Array.from({ length: r.stars }).map((_, i) => (
))}
“{r.text}”
— {r.name}
))}
);
}
// ---------- FAQ ----------
function FAQ() {
return (
Frequently Asked Questions
How does online reservation work?
Pick a unit and reserve it with your name and contact info. We'll hold the rate and confirm details via phone or email. Pay when you move in.
Do I need climate control?
For electronics, wood furniture, photos, and long-term storage in hot/humid climates, climate control is strongly recommended.
What documents do I need?
A government-issued ID and a valid phone number or email address. Vehicle storage requires registration and proof of insurance.
);
}
// ---------- Footer ----------
function Footer() {
return (
);
}
function FloatingCTA() {
return (
Call Now
);
}