2025-04-07 13:47:59 +01:00
|
|
|
"use client";
|
2025-05-13 10:00:09 +01:00
|
|
|
import Image from "next/image";
|
2025-05-31 21:29:50 +01:00
|
|
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
|
|
|
|
2025-05-25 19:59:53 +01:00
|
|
|
import BottomFooter from "@components/BottomFooter";
|
2025-04-07 13:47:59 +01:00
|
|
|
|
2025-04-28 12:35:18 +01:00
|
|
|
const ContactUs = () => {
|
2025-05-31 21:29:50 +01:00
|
|
|
// Form/modal
|
|
|
|
|
const [formData, setFormData] = useState({ name: "", email: "", message: "" });
|
|
|
|
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
|
|
|
|
|
|
|
|
// 1. Lava (Instagram): state & timer
|
|
|
|
|
const [lavaActive, setLavaActive] = useState(false);
|
|
|
|
|
const lavaTimeout = useRef<NodeJS.Timeout | null>(null);
|
|
|
|
|
|
|
|
|
|
// 2. Pulsating Map (Facebook): state & timer
|
|
|
|
|
const [pulsatingActive, setPulsatingActive] = useState(false);
|
|
|
|
|
const pulsatingTimeout = useRef<NodeJS.Timeout | null>(null);
|
|
|
|
|
|
|
|
|
|
// 3. Shake (LinkedIn): state & timer
|
|
|
|
|
const [shaking, setShaking] = useState(false);
|
|
|
|
|
const shakeTimeout = useRef<NodeJS.Timeout | null>(null);
|
2025-04-28 19:03:29 +01:00
|
|
|
|
2025-05-31 21:29:50 +01:00
|
|
|
// 4. Crack & Collapse (X): state & timer
|
|
|
|
|
const [showCracks, setShowCracks] = useState(false);
|
|
|
|
|
const [collapse, setCollapse] = useState(false);
|
|
|
|
|
const crackTimeout = useRef<NodeJS.Timeout | null>(null);
|
|
|
|
|
|
|
|
|
|
// Lava flood handler (top-down flood)
|
|
|
|
|
const handleInstagramClick = useCallback((e: React.MouseEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
setLavaActive(true);
|
|
|
|
|
if (lavaTimeout.current) clearTimeout(lavaTimeout.current);
|
|
|
|
|
lavaTimeout.current = setTimeout(() => setLavaActive(false), 2000);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// Pulsating Map handler
|
|
|
|
|
const handleFacebookClick = useCallback((e: React.MouseEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
setPulsatingActive(true);
|
|
|
|
|
if (pulsatingTimeout.current) clearTimeout(pulsatingTimeout.current);
|
|
|
|
|
pulsatingTimeout.current = setTimeout(() => setPulsatingActive(false), 2000);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// LinkedIn shake handler
|
|
|
|
|
const handleLinkedInClick = useCallback(
|
|
|
|
|
(e: React.MouseEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
if (shaking) return;
|
|
|
|
|
setShaking(true);
|
|
|
|
|
const body = document.body;
|
|
|
|
|
body.classList.remove("shake-screen");
|
|
|
|
|
void body.offsetWidth;
|
|
|
|
|
body.classList.add("shake-screen");
|
|
|
|
|
if (shakeTimeout.current) clearTimeout(shakeTimeout.current);
|
|
|
|
|
shakeTimeout.current = setTimeout(() => {
|
|
|
|
|
setShaking(false);
|
|
|
|
|
body.classList.remove("shake-screen");
|
|
|
|
|
}, 1000);
|
|
|
|
|
},
|
|
|
|
|
[shaking]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// X (crack and collapse) handler
|
|
|
|
|
const handleXClick = useCallback((e: React.MouseEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
setShowCracks(true);
|
|
|
|
|
if (crackTimeout.current) clearTimeout(crackTimeout.current);
|
|
|
|
|
crackTimeout.current = setTimeout(() => {
|
|
|
|
|
setCollapse(true);
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
setShowCracks(false);
|
|
|
|
|
setCollapse(false);
|
|
|
|
|
}, 1500);
|
|
|
|
|
}, 1000);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// Clean up timeouts and shake class
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
return () => {
|
|
|
|
|
if (lavaTimeout.current) clearTimeout(lavaTimeout.current);
|
|
|
|
|
if (pulsatingTimeout.current) clearTimeout(pulsatingTimeout.current);
|
|
|
|
|
if (shakeTimeout.current) clearTimeout(shakeTimeout.current);
|
|
|
|
|
if (crackTimeout.current) clearTimeout(crackTimeout.current);
|
|
|
|
|
document.body.classList.remove("shake-screen");
|
|
|
|
|
};
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// Form handlers
|
|
|
|
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
2025-04-28 19:03:29 +01:00
|
|
|
setFormData({ ...formData, [e.target.name]: e.target.value });
|
|
|
|
|
};
|
2025-05-31 21:29:50 +01:00
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
2025-04-28 19:03:29 +01:00
|
|
|
e.preventDefault();
|
|
|
|
|
console.log("Form submitted with data:", formData);
|
2025-05-31 21:29:50 +01:00
|
|
|
setIsModalOpen(true);
|
2025-04-28 19:03:29 +01:00
|
|
|
setFormData({ name: "", email: "", message: "" });
|
|
|
|
|
};
|
2025-04-28 12:35:18 +01:00
|
|
|
|
2025-04-28 19:03:29 +01:00
|
|
|
return (
|
2025-04-29 16:52:03 +01:00
|
|
|
<div className="h-full relative text-white border border-black overflow-hidden">
|
2025-05-31 21:29:50 +01:00
|
|
|
{/* Lava Flood Overlay */}
|
|
|
|
|
{lavaActive && (
|
|
|
|
|
<div className="lava-flood-overlay lava-active fixed inset-0 z-[60] flex items-center justify-center">
|
|
|
|
|
<img
|
|
|
|
|
src="/lava.jpg"
|
|
|
|
|
alt="Lava flood"
|
|
|
|
|
draggable={false}
|
|
|
|
|
className="w-full h-full object-cover opacity-80 pointer-events-none"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{/* Pulsating Overlay */}
|
|
|
|
|
{pulsatingActive && (
|
|
|
|
|
<div className="pulsating-map-overlay pulsating-active fixed inset-0 z-[60] flex items-center justify-center">
|
|
|
|
|
<img
|
|
|
|
|
src="/pulsatingMap.jpg"
|
|
|
|
|
alt="Pulsating Map"
|
|
|
|
|
draggable={false}
|
|
|
|
|
className="w-full h-full object-cover opacity-80 pointer-events-none"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{/* Crack & Collapse Overlay */}
|
|
|
|
|
{(showCracks || collapse) && (
|
|
|
|
|
<div
|
|
|
|
|
className={`crack-overlay fixed inset-0 z-[60] flex items-center justify-center${collapse ? " crack-collapse" : ""}`}
|
|
|
|
|
>
|
|
|
|
|
<img className="crack crack1 absolute w-3/4" src="/crack1.png" alt="" />
|
|
|
|
|
<img className="crack crack2 absolute w-3/4" src="/crack2.png" alt="" />
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{/* Modal: Submit Success */}
|
|
|
|
|
{isModalOpen && (
|
|
|
|
|
<div className="fixed inset-0 z-[70] flex items-center justify-center bg-black/60">
|
|
|
|
|
<div className="bg-white rounded-lg shadow-lg p-8 max-w-sm w-full text-center">
|
|
|
|
|
<h2 className="text-2xl font-bold mb-4 text-neutral-800">Thank You!</h2>
|
|
|
|
|
<p className="text-neutral-700 mb-6">Thank you for submitting a message. We will be responding via our email.</p>
|
|
|
|
|
<button
|
|
|
|
|
className="bg-blue-600 text-white px-5 py-2 rounded-lg font-medium hover:bg-blue-700 transition"
|
|
|
|
|
onClick={() => setIsModalOpen(false)}
|
|
|
|
|
>
|
|
|
|
|
Close
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2025-04-29 16:52:03 +01:00
|
|
|
<Image
|
|
|
|
|
height={5000}
|
|
|
|
|
width={5000}
|
|
|
|
|
alt="Logo"
|
|
|
|
|
className="border border-neutral-300 absolute z-10 -top-20"
|
|
|
|
|
src="/tsunamiWaves.jpg"
|
|
|
|
|
/>
|
2025-04-28 19:03:29 +01:00
|
|
|
{/* Overlay for readability */}
|
2025-05-09 10:30:12 +01:00
|
|
|
<div className="absolute overflow-hidden w-full h-full bg-gradient-to-b from-black/80 via-black/40 to-black/20 flex flex-col items-center z-20">
|
2025-04-28 19:03:29 +01:00
|
|
|
{/* Container */}
|
2025-04-29 16:52:03 +01:00
|
|
|
<div className="max-w-4xl mx-auto p-5 mt-20">
|
2025-04-28 19:03:29 +01:00
|
|
|
{/* Header */}
|
2025-05-09 10:30:12 +01:00
|
|
|
<h1 className="text-4xl font-bold text-center text-neutral-50 mb-6">Contact Us</h1>
|
2025-05-10 14:05:56 +01:00
|
|
|
<p className="text-lg text-center max-w-2xl text-neutral-200 mb-6">
|
2025-05-13 10:00:09 +01:00
|
|
|
Have questions or concerns about earthquakes, observatories or artefacts? Contact us via phone, email, social media or
|
|
|
|
|
using the form below with the relevant contact details.
|
2025-04-28 19:03:29 +01:00
|
|
|
</p>
|
|
|
|
|
<div className="flex flex-col md:flex-row gap-6">
|
|
|
|
|
{/* Contact Form Section */}
|
|
|
|
|
<div className="flex-1 bg-white bg-opacity-90 text-neutral-800 rounded-lg shadow-lg p-6">
|
|
|
|
|
<form onSubmit={handleSubmit}>
|
|
|
|
|
<div className="mb-4">
|
|
|
|
|
<label htmlFor="name" className="block text-neutral-700 font-medium mb-2">
|
|
|
|
|
Name
|
|
|
|
|
</label>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
name="name"
|
|
|
|
|
id="name"
|
|
|
|
|
value={formData.name}
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
placeholder="Your Name"
|
|
|
|
|
className="w-full p-3 border border-neutral-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
|
|
|
required
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mb-4">
|
|
|
|
|
<label htmlFor="email" className="block text-neutral-700 font-medium mb-2">
|
|
|
|
|
Email
|
|
|
|
|
</label>
|
|
|
|
|
<input
|
|
|
|
|
type="email"
|
|
|
|
|
name="email"
|
|
|
|
|
id="email"
|
|
|
|
|
value={formData.email}
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
placeholder="Your Email"
|
|
|
|
|
className="w-full p-3 border border-neutral-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
|
|
|
required
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mb-4">
|
|
|
|
|
<label htmlFor="message" className="block text-neutral-700 font-medium mb-2">
|
|
|
|
|
Message
|
|
|
|
|
</label>
|
|
|
|
|
<textarea
|
|
|
|
|
name="message"
|
|
|
|
|
id="message"
|
|
|
|
|
value={formData.message}
|
|
|
|
|
onChange={handleChange}
|
2025-04-29 16:52:03 +01:00
|
|
|
rows={5}
|
2025-04-28 19:03:29 +01:00
|
|
|
placeholder="Your Message"
|
|
|
|
|
className="w-full p-3 border border-neutral-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
|
|
|
required
|
2025-04-29 16:52:03 +01:00
|
|
|
style={{ resize: "none" }}
|
2025-04-28 19:03:29 +01:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<button
|
|
|
|
|
type="submit"
|
|
|
|
|
className="w-full bg-blue-600 text-white py-3 rounded-lg font-medium hover:bg-blue-700 transition duration-200"
|
|
|
|
|
>
|
|
|
|
|
Send Message
|
|
|
|
|
</button>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
{/* Contact Details Section */}
|
2025-04-29 16:52:03 +01:00
|
|
|
<div className="w-[45%] bg-white bg-opacity-90 text-neutral-800 rounded-lg shadow-lg p-6">
|
2025-05-10 14:05:56 +01:00
|
|
|
<h2 className="text-2xl font-bold text-neutral-800 mb-4">Get in Touch</h2>
|
2025-04-28 19:03:29 +01:00
|
|
|
<div className="mb-4">
|
2025-05-10 14:05:56 +01:00
|
|
|
<h3 className="text-neutral-700 font-bold font-large">Email</h3>
|
|
|
|
|
<a href="Mail to:getintouch@tremortracker.com font-medium" style={{ color: "initial" }}>
|
2025-04-29 16:52:03 +01:00
|
|
|
getintouch@tremortracker.com
|
|
|
|
|
</a>
|
2025-04-28 19:03:29 +01:00
|
|
|
</div>
|
|
|
|
|
<div className="mb-4">
|
2025-05-10 14:05:56 +01:00
|
|
|
<h3 className="text-neutral-700 font-bold font-large">Phone</h3>
|
|
|
|
|
<p className="text-neutral-600 font-medium">+44 7538 359022</p>
|
2025-04-28 19:03:29 +01:00
|
|
|
</div>
|
|
|
|
|
<div className="mb-4">
|
2025-05-10 14:05:56 +01:00
|
|
|
<h3 className="text-neutral-700 font-bold font-large">Address</h3>
|
2025-05-31 21:29:50 +01:00
|
|
|
<p className="text-neutral-600 font-medium">1 Sweentown Row, Greenwich, London, SE3 0FQ</p>
|
2025-04-28 19:03:29 +01:00
|
|
|
</div>
|
|
|
|
|
<h2 className="text-xl font-bold text-neutral-800 mb-4 mt-6">Follow Us</h2>
|
|
|
|
|
<div className="flex justify-around items-center">
|
2025-05-31 21:29:50 +01:00
|
|
|
{/* Instagram: Lava Flood */}
|
|
|
|
|
<a
|
|
|
|
|
href="#"
|
|
|
|
|
className="w-20 h-20 text-blue-600 hover:text-blue-800 transition duration-200"
|
|
|
|
|
aria-label="Instagram"
|
|
|
|
|
onClick={handleInstagramClick}
|
|
|
|
|
style={{ cursor: "pointer" }}
|
|
|
|
|
>
|
2025-04-28 19:03:29 +01:00
|
|
|
<span className="sr-only">Instagram</span>
|
|
|
|
|
<Image height={200} width={200} alt="Logo" className="z-10" src="/insta.webp" />
|
|
|
|
|
</a>
|
2025-05-31 21:29:50 +01:00
|
|
|
{/* Facebook: Pulsating Map */}
|
|
|
|
|
<a
|
|
|
|
|
href="#"
|
|
|
|
|
className="w-20 h-20 text-blue-600 hover:text-blue-800 transition duration-200"
|
|
|
|
|
aria-label="Facebook"
|
|
|
|
|
onClick={handleFacebookClick}
|
|
|
|
|
style={{ cursor: "pointer" }}
|
|
|
|
|
>
|
2025-04-28 19:03:29 +01:00
|
|
|
<span className="sr-only">Facebook</span>
|
|
|
|
|
<Image height={200} width={200} alt="Logo" className="z-10" src="/facebook.webp" />
|
|
|
|
|
</a>
|
2025-05-31 21:29:50 +01:00
|
|
|
{/* X: Crack & Collapse */}
|
|
|
|
|
<a
|
|
|
|
|
href="#"
|
|
|
|
|
className="w-20 h-20 p-4 text-blue-600 hover:text-blue-800 transition duration-200"
|
|
|
|
|
aria-label="X"
|
|
|
|
|
onClick={handleXClick}
|
|
|
|
|
style={{ cursor: "pointer" }}
|
|
|
|
|
>
|
2025-04-28 19:03:29 +01:00
|
|
|
<span className="sr-only">X</span>
|
|
|
|
|
<Image height={200} width={200} alt="Logo" className="z-10 rounded-lg" src="/x_logo.jpg" />
|
|
|
|
|
</a>
|
2025-05-31 21:29:50 +01:00
|
|
|
{/* LinkedIn: Shake */}
|
|
|
|
|
<a
|
|
|
|
|
href="#"
|
|
|
|
|
className="w-20 h-20 flex items-center text-blue-600 hover:text-blue-800 transition duration-200"
|
|
|
|
|
aria-label="LinkedIn"
|
|
|
|
|
onClick={handleLinkedInClick}
|
|
|
|
|
style={{ cursor: "pointer" }}
|
|
|
|
|
>
|
2025-04-28 19:03:29 +01:00
|
|
|
<span className="sr-only">LinkedIn</span>
|
|
|
|
|
<Image height={200} width={200} alt="Logo" className="z-10" src="/linkedIn.png" />
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-05-31 21:29:50 +01:00
|
|
|
<BottomFooter />
|
2025-04-28 19:03:29 +01:00
|
|
|
</div>
|
|
|
|
|
);
|
2025-04-28 12:35:18 +01:00
|
|
|
};
|
|
|
|
|
|
2025-04-28 19:03:29 +01:00
|
|
|
export default ContactUs;
|