Compare commits

..

11 Commits

Author SHA1 Message Date
06e215a209 Merge branch 'master' of gitea.thowitz.com:thowitz-work/tremor-tracker 2025-05-30 12:26:25 +01:00
Emily Neighbour
04307562a4 removing unnecessary images 2025-05-28 22:42:11 +01:00
Emily Neighbour
d6f7d73622 removed sidebar bits 2025-05-28 22:37:28 +01:00
Emily Neighbour
803253b96e Merge branch 'master' of ssh://stash.dyson.global.corp:7999/~thowitz/tremor-tracker 2025-05-28 22:31:57 +01:00
Emily Neighbour
2c033028cf bottom footer fix 2025-05-28 22:31:45 +01:00
Emily Neighbour
3cb2033046 learn page format alignment 2025-05-28 22:27:58 +01:00
IZZY
1f005295b4 we have a search modal it just doesnt work yet 2025-05-28 22:11:39 +01:00
c1d686b012 Merge branch 'master' of ssh://stash.dyson.global.corp:7999/~thowitz/tremor-tracker 2025-05-28 15:45:14 +01:00
Emily Neighbour
c3ecca40f2 new the team image 2025-05-28 08:52:30 +01:00
IZZY
d5da39d812 Added a pretty background 2025-05-27 16:43:22 +01:00
IZZY
977c35bd57 Working Shop and footer 2025-05-27 13:48:32 +01:00
23 changed files with 468 additions and 481 deletions

View File

@ -93,7 +93,7 @@ model Artefact {
earthquake Earthquake @relation(fields: [earthquakeId], references: [id])
creatorId Int?
creator User? @relation("UserArtefactCreator", fields: [creatorId], references: [id], onDelete: NoAction, onUpdate: NoAction)
isRequired Boolean @default(true)
isRequired Boolean @default(true) @map("isRequired")
dateAddedToShop DateTime?
shopPrice Float?
isSold Boolean @default(false)

BIN
public/BlueBackground.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
public/EarthHighRes.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 KiB

BIN
public/earthquakeRelief.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 KiB

BIN
public/tectonicPlates.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

@ -0,0 +1,18 @@
import { NextResponse } from "next/server";
import { prisma } from "@utils/prisma";
export async function GET(request: Request) {
try {
const artefact = await prisma.artefact.findMany();
return NextResponse.json({
message: "Got artefacts successfully",
artefact
}, { status: 200 });
} catch (error) {
console.error("Error in artefacts endpoint:", error);
return NextResponse.json({ message: "Internal Server Error" }, { status: 500 });
}
}

View File

@ -2,20 +2,100 @@
import { useMemo, useState } from "react";
import useSWR from "swr";
import Map from "@components/Map";
import Sidebar from "@components/Sidebar";
import { createPoster } from "@utils/axiosHelpers";
import { Earthquake } from "@prismaclient";
import { getRelativeDate } from "@utils/formatters";
import GeologicalEvent from "@appTypes/Event";
import axios from "axios";
// --- SEARCH MODAL COMPONENT ---
function EarthquakeSearchModal({ open, onClose, onSelect }) {
const [search, setSearch] = useState("");
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
const handleSearch = async (e) => {
e.preventDefault();
setLoading(true);
setResults([]);
try {
const res = await axios.post("/api/earthquakes/search", { query: search });
setResults(res.data.earthquakes || []);
} catch (e) {
alert("Failed to search.");
}
setLoading(false);
};
if (!open) return null;
return (
<div className="fixed z-50 inset-0 bg-black/40 flex items-center justify-center">
<div className="bg-white rounded-lg shadow-lg p-6 max-w-lg w-full relative">
<button
onClick={onClose}
className="absolute right-4 top-4 text-gray-500 hover:text-black text-lg"
>
&times;
</button>
<h2 className="font-bold text-xl mb-4">Search Earthquakes</h2>
<form onSubmit={handleSearch} className="flex gap-2 mb-4">
<input
type="text"
placeholder="e.g. Mexico, EV-7.4-Mexico-00035"
value={search}
onChange={e => setSearch(e.target.value)}
className="flex-grow px-3 py-2 border rounded"
required
/>
<button
type="submit"
className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
>
{loading ? "Searching..." : "Search"}
</button>
</form>
<div>
{results.length === 0 && !loading && search !== "" && (
<p className="text-gray-400 text-sm">No results found.</p>
)}
<ul>
{results.map(eq => (
<li
key={eq.id}
className="border-b py-2 cursor-pointer hover:bg-gray-50 flex items-center justify-between"
onClick={() => { onSelect(eq); onClose(); }}
tabIndex={0}
>
<div>
<strong>{eq.code}</strong> {" "}
<span>{eq.location}</span> <span className="text-xs text-gray-500">{new Date(eq.date).toLocaleDateString()}</span>
</div>
<div className={`rounded-full px-2 py-1 ml-2 text-white font-semibold ${eq.magnitude >= 7 ? "bg-red-500" : eq.magnitude >= 6 ? "bg-orange-400" : "bg-yellow-400"}`}>
{eq.magnitude}
</div>
</li>
))}
</ul>
</div>
</div>
</div>
);
}
// --- MAIN PAGE COMPONENT ---
export default function Earthquakes() {
const [selectedEventId, setSelectedEventId] = useState("");
const [hoveredEventId, setHoveredEventId] = useState("");
// todo properly integrate loading
// Search modal state
const [searchModalOpen, setSearchModalOpen] = useState(false);
// Fetch recent earthquakes as before
const { data, error, isLoading } = useSWR("/api/earthquakes", createPoster({ rangeDaysPrev: 5 }));
// Prepare events for maps/sidebar
const earthquakeEvents = useMemo(
() =>
data && data.earthquakes
@ -32,11 +112,14 @@ export default function Earthquakes() {
date: x.date,
})
)
.sort((a: GeologicalEvent, b: GeologicalEvent) => new Date(b.date).getTime() - new Date(a.date).getTime()) // Remove Date conversion
.sort((a: GeologicalEvent, b: GeologicalEvent) => new Date(b.date).getTime() - new Date(a.date).getTime())
: [],
[data]
);
// Optional: show details of selected search result (not implemented here)
// const [selectedSearchResult, setSelectedSearchResult] = useState(null);
return (
<div className="flex h-[calc(100vh-3.5rem)] w-full overflow-hidden">
<div className="flex-grow h-full">
@ -60,6 +143,15 @@ export default function Earthquakes() {
setHoveredEventId={setHoveredEventId}
button1Name="Log an Earthquake"
button2Name="Search Earthquakes"
onButton2Click={() => setSearchModalOpen(true)} // <-- important!
/>
<EarthquakeSearchModal
open={searchModalOpen}
onClose={() => setSearchModalOpen(false)}
onSelect={eq => {
setSelectedEventId(eq.code); // select on map/sidebar
// setSelectedSearchResult(eq); // you can use this if you want to show detail modal
}}
/>
</div>
);

View File

@ -0,0 +1,25 @@
import { NextResponse } from "next/server";
import { prisma } from "@utils/prisma";
export async function POST(req: Request) {
try {
const { query } = await req.json();
// Find earthquakes where either code or location matches (case-insensitive)
const earthquakes = await prisma.earthquake.findMany({
where: {
OR: [
{ code: { contains: query, mode: "insensitive" } },
{ location: { contains: query, mode: "insensitive" } }
],
},
orderBy: { date: "desc" },
take: 20, // limit results
});
return NextResponse.json({ earthquakes, message: "Success" });
} catch (error) {
console.error("Error in earthquake search", error);
return NextResponse.json({ message: "Internal Server Error" }, { status: 500 });
}
}

View File

@ -1,48 +1,53 @@
// app/learn/page.tsx
"use client";
import BottomFooter from "@components/BottomFooter";
export default function LearnPage() {
return (
<div className="min-h-screen bg-blue-50 flex flex-col">
{/* (Optional) Navbar */}
{/* <Navbar /> */}
<div
className="min-h-screen bg-fixed bg-cover bg-center flex flex-col relative"
style={{
backgroundImage: "url('/earthquakeRelief.jpg')", // adjust path as needed
}}
>
{/* Overlay for readability */}
<div className="absolute inset-0 bg-black bg-opacity-50"></div>
<main className="flex-1 flex flex-col items-center justify-start pt-12 px-4">
<h1 className="text-4xl font-bold mb-4 text-blue-800 text-center">Earthquakes</h1>
<p className="max-w-2xl text-lg text-gray-700 mb-6 text-center">
<span className="font-bold">In this page, you can learn all about what earthquakes are, and how to keep safe!</span>
<main className="flex-1 flex flex-col items-center justify-start pt-16 px-4 relative z-20">
{/* Title & subtitle OVER the background (not in the content box) */}
<h1 className="text-4xl font-bold mb-4 text-white text-center drop-shadow-lg">Earthquakes</h1>
<p className="max-w-2xl text-lg text-white mb-8 text-center font-bold drop-shadow">
In this page, you can learn all about what earthquakes are, and how best to keep safe!
</p>
<div className="max-w-3xl text-base text-gray-600 text-left space-y-8">
{/* Content box: all following info INSIDE */}
<div className="max-w-4xl w-full bg-white bg-opacity-90 rounded-xl shadow-2xl mx-auto mb-12 p-8 md:p-10">
{/* Section 1 */}
<section>
<section className="mb-8">
<p>
<span className="font-semibold text-blue-800">What are earthquakes?</span>
<span className="font-bold text-black md:text-xl">What are earthquakes?</span>
<br />
Earthquakes are a shaking of the earth's surface caused by a sudden release of energy underground. They can range in
size, from tiny trembles to large quakes, which can cause destruction and even tsunamis. Hundreds of earthquakes
happen every daybut most are too small to feel.
</p>
</section>
{/* Section 2 */}
<section>
<section className="mb-8">
<p>
<span className="font-semibold text-blue-800">What are the types of earthquakes?</span>
<span className="font-bold text-black md:text-xl">What are the types of earthquakes?</span>
<br />
Regions near plate boundaries, such as around the Pacific Ocean ("The Ring of Fire"), experience the most activity.
</p>
</section>
{/* Section 3 */}
<section>
<p>
<span className="font-semibold text-blue-800">How can I be prepared?</span>
<span className="font-bold text-black md:text-xl">How can I be prepared?</span>
</p>
{/* MAIN BULLET POINTS */}
<ul className="list-disc list-inside pl-6 space-y-2">
<li>
<span className="font-bold text-gray-800">Assemble an emergency kit:</span>
<span className="font-bold text-gray-800 ">Assemble an emergency kit:</span>
This should be stored in your earthquake emergency zone. It may be useful, as in an earthquake, you may lose
electricity or water supplies.
{/* SUB BULLETS */}

View File

@ -1,5 +1,6 @@
import Image from "next/image";
import Link from "next/link";
import BottomFooter from "@components/BottomFooter";
export default function Home() {
@ -16,10 +17,7 @@ export default function Home() {
</div>
<p className="mt-2"></p>
<div className="flex flex-col md:flex-row md:justify-evenly gap-6 mt-2">
<Link
href="/earthquakes"
className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300"
>
<Link href="/earthquakes" className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300">
<Image height={100} width={100} src="/earthquake.png" alt="Education Icon" className="h-40 w-40 mb-4" />
<h3 className="text-xl font-bold text-black mb-4">Earthquakes</h3>
<p className="text-md text-black text-center max-w-xs opacity-90">
@ -36,10 +34,7 @@ export default function Home() {
Find recently active observatories, and newly opened/closed sites
</p>
</Link>
<Link
href="/shop"
className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300"
>
<Link href="/shop" className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300">
<Image height={100} width={100} src="/artifactIcon.jpg" alt="Technology Icon" className="h-40 w-40 mb-4" />
<h3 className="text-xl font-bold text-black mb-4">Artefacts</h3>
<p className="text-md text-black text-center max-w-xs opacity-90">
@ -59,11 +54,16 @@ export default function Home() {
Welcome to Tremor Tracker
</h1>
<p className="text-lg md:text-xl font-sans text-white w-4/6 mx-auto drop-shadow-md z-10">
TremorTracker is a non-profit website and research company, that aims to provide true, reliable data. Our mission is seismic education and preparation for all
TremorTracker is a non-profit website and research company, that aims to provide true, reliable data. Our mission
is seismic education and preparation for all
</p>
<p className="mt-20"></p>
<p className="text-lg md:text-3xl font-bold text-white w-4/6 mx-auto drop-shadow-md z-10">What is an earthquake?</p>
<p className="text-lg md:text-xl text-white w-4/6 mx-auto drop-shadow-md z-10">info</p>
<p className="text-lg md:text-xl text-white w-4/6 mx-auto drop-shadow-md z-10">
Earthquakes are a shaking of the earth's surface caused by a sudden release of energy underground. They can range
in size, from tiny trembles to large quakes, which can cause destruction and even tsunamis. Hundreds of
earthquakes happen every daybut most are too small to feel.
</p>
<p className="mt-20"></p>
<p className="text-lg md:text-3xl font-bold text-white w-4/6 mx-auto drop-shadow-md z-10">
How do we log earthquakes?
@ -107,30 +107,21 @@ export default function Home() {
</section>
<p className="mt-2"></p>
<div className="flex flex-col md:flex-row md:justify-evenly gap-6 mt-2">
<Link
href="/contact-us"
className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300"
>
<Link href="/contact-us" className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300">
<Image height={100} width={100} src="/contactUs.jpg" alt="Education Icon" className="h-20 w-20 mb-4" />
<h3 className="text-xl font-bold text-black mb-4">Contact us directly</h3>
<p className="text-md text-black text-center max-w-xs opacity-90">
Visit our socials or leave us a message via phone or email.
</p>
</Link>
<Link
href="/our-mission"
className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300"
>
<Link href="/our-mission" className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300">
<Image height={100} width={100} src="/mission.jpg" alt="Research Icon" className="h-20 w-20 mb-4" />
<h3 className="text-xl font-bold text-black mb-4">Our Mission</h3>
<p className="text-md text-black text-center max-w-xs opacity-90">
Find out more about our purpose and the features we offer.
</p>
</Link>
<Link
href="/the-team"
className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300"
>
<Link href="/the-team" className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300">
<Image height={100} width={100} src="/team.jpg" alt="Technology Icon" className="h-20 w-20 mb-4" />
<h3 className="text-xl font-bold text-black mb-4">Meet the Team</h3>
<p className="text-md text-black text-center max-w-xs opacity-90">
@ -139,7 +130,7 @@ export default function Home() {
</Link>
</div>
<p className="mt-10"></p>
<section style={{ height: 500}} className="text-black">
<section style={{ height: 500 }} className="text-black">
<div className="w-full relative overflow-hidden z=10">
<div className="">
<Image height={1000} width={2000} alt="Background Image" src="/scientists.png"></Image>

View File

@ -1,191 +1,46 @@
"use client";
import Image from "next/image";
import { Dispatch, SetStateAction, useCallback, useState } from "react";
import { Dispatch, SetStateAction, useCallback, useState, useEffect } from "react";
import BottomFooter from "@components/BottomFooter";
import { ExtendedArtefact } from "@appTypes/ApiTypes";
import { Currency } from "@appTypes/StoreModel";
import { useStoreState } from "@hooks/store";
const artefacts: ExtendedArtefact[] = [
{
id: 1,
name: "Golden Scarab",
description: "An ancient Egyptian artefact symbolizing rebirth.",
location: "Cairo, Egypt",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact1.jpg",
price: 150,
},
{
id: 2,
name: "Aztec Sunstone",
description: "A replica of the Aztec calendar (inscriptions intact).",
location: "Peru",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact2.jpg",
price: 200,
},
{
id: 3,
name: "Medieval Chalice",
description: "Used by royalty in medieval ceremonies.",
location: "Cambridge, England",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact3.jpg",
price: 120,
},
{
id: 4,
name: "Roman Coin",
description: "An authentic Roman coin from the 2nd century CE.",
location: "Rome, Italy",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact4.jpg",
price: 80,
},
{
id: 5,
name: "Samurai Mask",
description: "Replica of Japanese Samurai battle masks.",
location: "Tokyo, Japan",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact5.jpg",
price: 300,
},
{
id: 6,
name: "Ancient Greek Vase",
description: "Depicts Greek mythology, found in the Acropolis.",
location: "Athens, Greece",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact6.jpg",
price: 250,
},
{
id: 7,
name: "Incan Pendant",
description: "Represents the Sun God Inti.",
location: "India",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact7.jpg",
price: 175,
},
{
id: 8,
name: "Persian Carpet Fragment",
description: "Ancient Persian artistry.",
location: "Petra, Jordan",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact8.jpg",
price: 400,
},
{
id: 9,
name: "Stone Buddha",
description: "Authentic stone Buddha carving.",
location: "India",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact9.jpg",
price: 220,
},
{
id: 10,
name: "Victorian Brooch",
description: "A beautiful Victorian-era brooch with a ruby centre.",
location: "Oxford, England",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact10.jpg",
price: 150,
},
{
id: 11,
name: "Ancient Scroll",
description: "A mysterious scroll from ancient times.",
location: "Madrid, Spain",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact11.jpg",
price: 500,
},
{
id: 12,
name: "Ming Dynasty Porcelain",
description: "Porcelain from China's Ming Dynasty.",
location: "Beijing, China",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact12.jpg",
price: 300,
},
{
id: 13,
name: "African Tribal Mask",
description: "A unique tribal mask from Africa.",
location: "Nigeria",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact13.jpg",
price: 250,
},
{
id: 14,
name: "Crystal Skull",
description: "A mystical pre-Columbian artefact.",
location: "Colombia",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact14.jpg",
price: 1000,
},
{
id: 15,
name: "Medieval Armor Fragment",
description: "A fragment of medieval armor.",
location: "Normandy, France",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact15.jpg",
price: 400,
},
{
id: 16,
name: "Medieval Helmet Fragment",
description: "A fragment of a medieval helmet.",
location: "Normandy, France",
earthquakeID: "h",
observatory: "jhd",
dateReleased: "12/02/2025",
image: "/artefact16.jpg",
price: 500,
},
];
export default function Shop() {
const [artefacts, setArtefacts] = useState<ExtendedArtefact[]>([]);
const [loading, setLoading] = useState(true);
// 3. Fetch from your API route and map data to fit your existing fields
useEffect(() => {
async function fetchArtefacts() {
setLoading(true);
try {
const res = await fetch("/api/artefacts");
const data = await res.json();
const transformed = data.artefact.map((a: any) => ({
id: a.id,
name: a.name,
description: a.description,
location: a.warehouseArea, // your database
earthquakeID: a.earthquakeId?.toString() ?? "",
observatory: a.type ?? "", // if you want to display type
dateReleased: a.createdAt ? new Date(a.createdAt).toLocaleDateString() : "",
image: "/artefactImages/" + (a.imageName || "NoImageFound.PNG"),
price: a.shopPrice ?? 100, // fallback price if not in DB
}));
setArtefacts(transformed);
} catch (e) {
// Optionally handle error
console.error("Failed to fetch artefacts", e);
} finally {
setLoading(false);
}
}
fetchArtefacts();
}, []);
const [currentPage, setCurrentPage] = useState(1);
const [selectedArtefact, setSelectedArtefact] = useState<Artefact | null>(null);
const [showPaymentModal, setShowPaymentModal] = useState(false);
@ -433,20 +288,20 @@ export default function Shop() {
}
return (
<div
className="min-h-screen relative flex flex-col"
className="min-h-screen bg-blue-50 relative flex flex-col"
style={{
backgroundImage: "url('/artefacts.jpg')",
backgroundImage: "url('/EarthHighRes.jpg')",
backgroundSize: "cover",
backgroundPosition: "center",
}}
>
<div className="absolute inset-0 bg-black bg-opacity-50 z-0"></div>
<div className="absolute inset-0 bg-black bg-opacity-0 z-0"></div>
<div className="relative z-10 flex flex-col items-center w-full px-2 py-12">
<h1 className="text-4xl md:text-4xl font-bold text-center text-white mb-2 tracking-tight drop-shadow-lg">
<h1 className="text-4xl md:text-4xl font-bold text-center text-blue-300 mb-2 tracking-tight drop-shadow-lg">
Artefact Shop
</h1>
<p className="text-lg md:text-xl text-center text-white mb-10 drop-shadow-md max-w-2xl">
Discover extraordinary historical artefacts and collectibles from major seismic events from around the world - now
Discover extraordinary artefacts and collectibles from major seismic events from around the world - Previously studied by our scientists, now
available for purchase.
</p>
<div className="w-full max-w-7xl grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-10 p-2">
@ -489,6 +344,10 @@ export default function Shop() {
{showThankYouModal && orderNumber && (
<ThankYouModal orderNumber={orderNumber} onClose={() => setShowThankYouModal(false)} />
)}
{!selectedArtefact && !showPaymentModal && !showThankYouModal && (
<div className="relative z-50">
<BottomFooter />
</div>
);
}
)}
</div>
);

View File

@ -33,7 +33,7 @@ export default function Page() {
return (
<div
className="min-h-screen relative flex flex-col items-center justify-center px-4 py-30"
style={{ backgroundImage: "url('tectonicPlate.jpg')", backgroundSize: "cover", backgroundPosition: "center" }}
style={{ backgroundImage: "url('tectonicPlates.png')", backgroundSize: "cover", backgroundPosition: "center" }}
>
{/* Overlay */}
<div className="absolute inset-0 bg-black bg-opacity-50 pointer-events-none"></div>

View File

@ -1,10 +1,10 @@
// components/Footer.tsx
import Link from "next/link";
import { FaTwitter, FaFacebook, FaYoutube, FaLinkedin } from "react-icons/fa";
import { FaFacebook, FaLinkedin, FaTwitter, FaYoutube } from "react-icons/fa";
export default function Footer() {
return (
<footer className="bg-[#16424b] text-white pt-12 pb-4 px-6 mt-12">
<footer className="bg-[#16424b] text-white pt-12 pb-4 px-6 mt-12 z-0">
<div className="max-w-6xl mx-auto flex flex-col md:flex-row justify-between gap-8">
{/* Useful Links */}
<div className="min-w-[200px] mb-8 md:mb-0 flex-1">
@ -21,14 +21,12 @@ export default function Footer() {
</Link>
</li>
<li>
<Link href="https://www.dysoninstitute.ac.uk/about-us/governance/privacy-notices/"
className="hover:underline">
<Link href="https://www.dysoninstitute.ac.uk/about-us/governance/privacy-notices/" className="hover:underline">
Privacy policy
</Link>
</li>
<li>
<Link href="https://privacy.dyson.com/en/globalcookiepolicy.aspx"
className="hover:underline">
<Link href="https://privacy.dyson.com/en/globalcookiepolicy.aspx" className="hover:underline">
Cookies policy
</Link>
</li>
@ -60,25 +58,13 @@ export default function Footer() {
<div className="flex space-x-3">
{/* Replace src with your icon URLs, or use next/image if preferred */}
<a href="#" target="_blank" rel="noopener noreferrer">
<img
src="instagram.png"
alt="instagram"
className="h-7 w-7 rounded-full shadow"
/>
<img src="instagram.png" alt="instagram" className="h-7 w-7 rounded-full shadow" />
</a>
<a href="#" target="_blank" rel="noopener noreferrer">
<img
src="linkedin.png"
alt="linkedin"
className="h-7 w-7 rounded-full shadow"
/>
<img src="linkedin.png" alt="linkedin" className="h-7 w-7 rounded-full shadow" />
</a>
<a href="#" target="_blank" rel="noopener noreferrer">
<img
src="x_logo.jpg"
alt="X"
className="h-7 w-7 rounded-full shadow"
/>
<img src="x_logo.jpg" alt="X" className="h-7 w-7 rounded-full shadow" />
</a>
</div>
</div>

View File

@ -0,0 +1,87 @@
import Link from "next/link";
import React, { Dispatch, SetStateAction, useState } from "react";
import { TbHexagon } from "react-icons/tb";
import Event from "@appTypes/Event";
import getMagnitudeColor from "@utils/getMagnitudeColour";
function setButton1(button1Name) {
const [modalOpen, setModalOpen] = useState(false);
return (
modalOpen && (
<div className="fixed z-50 inset-0 bg-black bg-opacity-50 flex items-center justify-center">
<div className="bg-white rounded-lg shadow-lg max-w-6xl w-full p-10">
<div className="flex items-center justify-between mb-3">
<h2 className="text-2xl font-extrabold">Log New Earthquake</h2>
<button
onClick={() => setModalOpen(false)}
className="text-2xl font-bold text-gray-500 hover:text-gray-900"
aria-label="Close modal"
>
&times;
</button>
</div>
{/* Blank Table */}
<table className="w-full border mb-4">
<thead>
<tr>
<th className="border px-2 py-1">Date</th>
<th className="border px-2 py-1">Code</th>
<th className="border px-2 py-1">Magnitude</th>
<th className="border px-2 py-1">Observatory</th>
<th className="border px-2 py-1">Type</th>
<th className="border px-2 py-1">Latitude</th>
<th className="border px-2 py-1">Longitude</th>
<th className="border px-2 py-1">Location</th>
<th className="border px-2 py-1">Observatory</th>
<th className="border px-2 py-1">Depth</th>
</tr>
</thead>
<tbody>
<tr>
<td className="border px-2 py-1">
<input type="date" className="border p-1 w-full" disabled />
</td>
<td className="border px-2 py-1">
<input type="number" className="border p-1 w-full" disabled />
</td>
<td className="border px-2 py-1">
<input type="text" className="border p-1 w-full" disabled />
</td>
<td className="border px-2 py-1">
<input type="text" className="border p-1 w-full" disabled />
</td>
<td className="border px-2 py-1">
<input type="text" className="border p-1 w-full" disabled />
</td>
<td className="border px-2 py-1">
<input type="date" className="border p-1 w-full" disabled />
</td>
<td className="border px-2 py-1">
<input type="number" className="border p-1 w-full" disabled />
</td>
<td className="border px-2 py-1">
<input type="text" className="border p-1 w-full" disabled />
</td>
<td className="border px-2 py-1">
<input type="text" className="border p-1 w-full" disabled />
</td>
<td className="border px-2 py-1">
<input type="text" className="border p-1 w-full" disabled />
</td>
</tr>
</tbody>
</table>
<div className="flex justify-end gap-4">
<button onClick={() => setModalOpen(true)} className="bg-blue-600 text-white px-10 py-2 rounded">
Add
</button>
<button onClick={() => setModalOpen(false)} className="bg-blue-600 text-white px-4 py-2 rounded">
Close
</button>
</div>
</div>
</div>
)
);
}

View File

@ -16,6 +16,7 @@ interface SidebarProps {
setHoveredEventId: Dispatch<SetStateAction<string>>;
button1Name: string;
button2Name: string;
onButton2Click?: () => void;
}
function MagnitudeNumber({ magnitude }: { magnitude: number }) {
@ -47,6 +48,7 @@ export default function Sidebar({
setHoveredEventId,
button1Name,
button2Name,
onButton2Click,
}: SidebarProps) {
const eventsContainerRef = useRef<HTMLDivElement>(null);
@ -68,16 +70,20 @@ export default function Sidebar({
<div className="px-6 pb-8 border-b border-neutral-200">
<h2 className="text-2xl font-bold text-neutral-800 mb-2">{logTitle}</h2>
<p className="text-sm text-neutral-600 leading-relaxed">{logSubtitle}</p>
<Link href="/">
<button className="mt-4 w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors duration-200 font-medium">
{button1Name}
</button>
</Link>
<Link href="/">
<button className="mt-4 w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors duration-200 font-medium">
{/* "Search Earthquakes" should NOT be wrapped in a Link! */}
<button
className="mt-4 w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors duration-200 font-medium"
onClick={onButton2Click}
type="button"
>
{button2Name}
</button>
</Link>
</div>
<div className="px-6 pt-6">
<h2 className="text-xl font-bold text-neutral-800 mb-4">{recentsTitle}</h2>

View File

@ -1,42 +0,0 @@
import Link from "next/link";
import React from "react";
const Sidebar = () => {
return (
<div className="flex flex-col h-screen w-64 bg-neutral-400 text-white border-l border-neutral-700">
<div className="flex flex-col p-4 border-b border-neutral-700">
<h2 className="text-xl font-semibold mb-2">Log an Earthquake</h2>
<p className="text-sm text-neutral-700">
Record new earthquakes - time/date, location, magnitude, observatory and scientists
</p>
<button className="mt-4 bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded">
<Link href="/">Log Event</Link>
</button>
</div>
{/* Section: Recent Events - Will need to be replaced with a link to the database*/}
<div className="flex-1 p-4">
<h2 className="text-xl font-semibold mb-2">Recent Events</h2>
<ul className="space-y-2">
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
<p className="text-sm">Earthquake in California</p>
<p className="text-xs text-neutral-300">Magnitude 5.3</p>
<p className="text-xs text-neutral-400">2 hours ago</p>
</li>
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
<p className="text-sm">Tremor in Japan</p>
<p className="text-xs text-neutral-300">Magnitude 4.7</p>
<p className="text-xs text-neutral-400">5 hours ago</p>
</li>
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
<p className="text-sm">Tremor in Spain</p>
<p className="text-xs text-neutral-300">Magnitude 2.1</p>
<p className="text-xs text-neutral-400">10 hours ago</p>
</li>
</ul>
</div>
</div>
);
};
export default Sidebar;

View File

@ -1,40 +0,0 @@
import Link from "next/link";
import React from "react";
const Sidebar = () => {
return (
<div className="flex flex-col h-screen w-64 bg-neutral-400 text-white border-l border-neutral-700">
<div className="flex flex-col p-4 border-b border-neutral-700">
<h2 className="text-xl font-semibold mb-2">Observatories</h2>
<p className="text-sm text-neutral-700">Observatory events - location, scientists, recent earthquakes</p>
<button className="mt-4 bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded">
<Link href="/">Observatory News</Link>
</button>
</div>
{/* Section: Recent Events - Will need to be replaced with a link to the database*/}
<div className="flex-1 p-4">
<h2 className="text-xl font-semibold mb-2">Recent Observatory Events</h2>
<ul className="space-y-2">
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
<p className="text-sm">Earthquake in California</p>
<p className="text-xs text-neutral-300">Magnitude 5.3</p>
<p className="text-xs text-neutral-400">Cali Observatory</p>
</li>
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
<p className="text-sm">Tremor in Japan</p>
<p className="text-xs text-neutral-300">Magnitude 4.7</p>
<p className="text-xs text-neutral-400">Kyoto Observatory</p>
</li>
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
<p className="text-sm">Tremor in Spain</p>
<p className="text-xs text-neutral-300">Magnitude 2.1</p>
<p className="text-xs text-neutral-400">Madrid Observatory</p>
</li>
</ul>
</div>
</div>
);
};
export default Sidebar;