diff --git a/package-lock.json b/package-lock.json
index 1f425f5..5accf57 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -28,7 +28,8 @@
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.27.1",
- "eslint-plugin-react-hooks": "^4.3.0"
+ "eslint-plugin-react-hooks": "^4.3.0",
+ "mkcert": "^3.2.0"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -10804,6 +10805,33 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/mkcert": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/mkcert/-/mkcert-3.2.0.tgz",
+ "integrity": "sha512-026Eivq9RoOjOuLJGzbhGwXUAjBxRX11Z7Jbm4/7lqT/Av+XNy9SPrJte6+UpEt7i+W3e/HZYxQqlQcqXZWSzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^11.0.0",
+ "node-forge": "^1.3.1"
+ },
+ "bin": {
+ "mkcert": "dist/cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/mkcert/node_modules/commander": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
@@ -23742,6 +23770,24 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
},
+ "mkcert": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/mkcert/-/mkcert-3.2.0.tgz",
+ "integrity": "sha512-026Eivq9RoOjOuLJGzbhGwXUAjBxRX11Z7Jbm4/7lqT/Av+XNy9SPrJte6+UpEt7i+W3e/HZYxQqlQcqXZWSzg==",
+ "dev": true,
+ "requires": {
+ "commander": "^11.0.0",
+ "node-forge": "^1.3.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
+ "dev": true
+ }
+ }
+ },
"mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
diff --git a/package.json b/package.json
index 1d9863d..2b81a01 100644
--- a/package.json
+++ b/package.json
@@ -1,47 +1,49 @@
{
- "name": "website-react",
- "version": "0.1.0",
- "private": true,
- "homepage": "https://waterloorocketry.com",
- "dependencies": {
- "@fortawesome/fontawesome-free": "^6.6.0",
- "@fortawesome/free-solid-svg-icons": "^6.6.0",
- "@fortawesome/react-fontawesome": "^0.2.2",
- "@testing-library/jest-dom": "^5.16.1",
- "@testing-library/react": "^11.2.7",
- "@testing-library/user-event": "^12.8.3",
- "bootstrap": "^5.3.1",
- "react": "^17.0.2",
- "react-bootstrap": "^2.0.3",
- "react-dom": "^17.0.2",
- "react-helmet": "^6.1.0",
- "react-router-dom": "^6.1.1",
- "react-scripts": "^5.0.1",
- "web-vitals": "^1.1.2"
- },
- "scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
- "eject": "react-scripts eject"
- },
- "browserslist": {
- "production": [
- ">0.2%",
- "not dead",
- "not op_mini all"
- ],
- "development": [
- "last 1 chrome version",
- "last 1 firefox version",
- "last 1 safari version"
- ]
- },
- "devDependencies": {
- "eslint-config-airbnb": "^19.0.2",
- "eslint-plugin-import": "^2.25.3",
- "eslint-plugin-jsx-a11y": "^6.5.1",
- "eslint-plugin-react": "^7.27.1",
- "eslint-plugin-react-hooks": "^4.3.0"
- }
+ "name": "website-react",
+ "version": "0.1.0",
+ "private": true,
+ "homepage": "https://waterloorocketry.com",
+ "dependencies": {
+ "@fortawesome/fontawesome-free": "^6.6.0",
+ "@fortawesome/free-solid-svg-icons": "^6.6.0",
+ "@fortawesome/react-fontawesome": "^0.2.2",
+ "@testing-library/jest-dom": "^5.16.1",
+ "@testing-library/react": "^11.2.7",
+ "@testing-library/user-event": "^12.8.3",
+ "bootstrap": "^5.3.1",
+ "react": "^17.0.2",
+ "react-bootstrap": "^2.0.3",
+ "react-dom": "^17.0.2",
+ "react-helmet": "^6.1.0",
+ "react-router-dom": "^6.1.1",
+ "react-scripts": "^5.0.1",
+ "web-vitals": "^1.1.2"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "start-https": "set HTTPS=true&&set SSL_CRT_FILE=cert.pem&&set SSL_KEY_FILE=key.pem&&react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "devDependencies": {
+ "eslint-config-airbnb": "^19.0.2",
+ "eslint-plugin-import": "^2.25.3",
+ "eslint-plugin-jsx-a11y": "^6.5.1",
+ "eslint-plugin-react": "^7.27.1",
+ "eslint-plugin-react-hooks": "^4.3.0",
+ "mkcert": "^3.2.0"
+ }
}
diff --git a/public/index.html b/public/index.html
index e537ccb..618bf3f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,42 +1,71 @@
-
-
-
-
-
-
-
-
-
- Waterloo Rocketry
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ Waterloo Rocketry
+
+
+
+
+
diff --git a/public/service-worker.js b/public/service-worker.js
new file mode 100644
index 0000000..e77027c
--- /dev/null
+++ b/public/service-worker.js
@@ -0,0 +1,71 @@
+// Cache name - update this when you want to force cache refresh
+const CACHE_NAME = "waterloo-rocketry-v1";
+
+// Files to cache
+const urlsToCache = [
+ "/",
+ "/index.html",
+ "/manifest.json",
+ "/favicon.ico",
+ "/logo192.png",
+ "/logo512.png",
+];
+
+// Install service worker and cache files
+self.addEventListener("install", (event) => {
+ event.waitUntil(
+ caches.open(CACHE_NAME).then((cache) => {
+ return cache.addAll(urlsToCache);
+ })
+ );
+});
+
+// Fetch cached resources
+self.addEventListener("fetch", (event) => {
+ event.respondWith(
+ caches.match(event.request).then((response) => {
+ // Cache hit - return response
+ if (response) {
+ return response;
+ }
+
+ // Clone the request because it's a stream and can only be consumed once
+ const fetchRequest = event.request.clone();
+
+ return fetch(fetchRequest).then((response) => {
+ // Check if we received a valid response
+ if (
+ !response ||
+ response.status !== 200 ||
+ response.type !== "basic"
+ ) {
+ return response;
+ }
+
+ // Clone the response because it's a stream and can only be consumed once
+ const responseToCache = response.clone();
+
+ caches.open(CACHE_NAME).then((cache) => {
+ cache.put(event.request, responseToCache);
+ });
+
+ return response;
+ });
+ })
+ );
+});
+
+// Clean up old caches when a new service worker takes over
+self.addEventListener("activate", (event) => {
+ event.waitUntil(
+ caches.keys().then((cacheNames) => {
+ return Promise.all(
+ cacheNames.map((cacheName) => {
+ if (cacheName !== CACHE_NAME) {
+ return caches.delete(cacheName);
+ }
+ })
+ );
+ })
+ );
+});
diff --git a/src/index.jsx b/src/index.jsx
index da023ce..3cb52b5 100644
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -1,170 +1,276 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import {
- Route, BrowserRouter, Routes,
-} from 'react-router-dom';
+import React from "react";
+import ReactDOM from "react-dom";
+import { Route, BrowserRouter, Routes } from "react-router-dom";
-import Navigation from './components/Navigation/Navigation';
-import Page from './components/Page';
-import Redirect from './components/Redirect/Redirect';
+import Navigation from "./components/Navigation/Navigation";
+import Page from "./components/Page";
+import Redirect from "./components/Redirect/Redirect";
// pages
-import Home from './routes/Home';
-import Competition from './routes/Competition';
-import Join from './routes/Join';
-import Awards from './routes/Awards';
+import Home from "./routes/Home";
+import Competition from "./routes/Competition";
+import Join from "./routes/Join";
+import Awards from "./routes/Awards";
-import Rockets from './routes/Rockets';
-import Sponsors from './routes/Sponsors';
-import Subsystems from './routes/Subsystems';
-import Team from './routes/Team';
-import Outreach from './routes/Outreach';
-import Contact from './routes/Contact';
-import Documentation from './routes/Documentation';
+import Rockets from "./routes/Rockets";
+import Sponsors from "./routes/Sponsors";
+import Subsystems from "./routes/Subsystems";
+import Team from "./routes/Team";
+import Outreach from "./routes/Outreach";
+import Contact from "./routes/Contact";
+import Documentation from "./routes/Documentation";
-import Footer from './components/Footer/Footer';
+import Footer from "./components/Footer/Footer";
-import Borealis from './routes/rocketPages/Borealis';
-import LeviathanOfTheSky from './routes/rocketPages/LeviathanOfTheSky';
-import KrakenOfTheSky from './routes/rocketPages/KrakenOfTheSky';
-import SharkOfTheSky from './routes/rocketPages/SharkOfTheSky';
-import UnexplodedOrdnance from './routes/rocketPages/UnexplodedOrdnance';
-import Vidar3 from './routes/rocketPages/Vidar3';
-import Vidar2 from './routes/rocketPages/Vidar2';
-import Vidar from './routes/rocketPages/Vidar';
-import SilverBrant from './routes/rocketPages/SilverBrant';
-import Eridani from './routes/rocketPages/Eridani';
-import WRT1 from './routes/rocketPages/WRT1';
-import ScrollToTop from './components/ScrollToTop/ScrollToTop';
+import Borealis from "./routes/rocketPages/Borealis";
+import LeviathanOfTheSky from "./routes/rocketPages/LeviathanOfTheSky";
+import KrakenOfTheSky from "./routes/rocketPages/KrakenOfTheSky";
+import SharkOfTheSky from "./routes/rocketPages/SharkOfTheSky";
+import UnexplodedOrdnance from "./routes/rocketPages/UnexplodedOrdnance";
+import Vidar3 from "./routes/rocketPages/Vidar3";
+import Vidar2 from "./routes/rocketPages/Vidar2";
+import Vidar from "./routes/rocketPages/Vidar";
+import SilverBrant from "./routes/rocketPages/SilverBrant";
+import Eridani from "./routes/rocketPages/Eridani";
+import WRT1 from "./routes/rocketPages/WRT1";
+import ScrollToTop from "./components/ScrollToTop/ScrollToTop";
-import 'bootstrap/dist/css/bootstrap.min.css';
-import './index.css';
+import "bootstrap/dist/css/bootstrap.min.css";
+import "./index.css";
ReactDOM.render(
-
-
-
-
-
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
-
-
-
- ,
-
- document.getElementById('root'),
+
+
+
+
+
+
+
+
+ }
+ />
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ ,
+ document.getElementById("root")
);
+
+// Register service worker
+if ("serviceWorker" in navigator) {
+ window.addEventListener("load", () => {
+ navigator.serviceWorker
+ .register("/service-worker.js")
+ .then((registration) => {
+ console.log(
+ "ServiceWorker registration successful:",
+ registration.scope
+ );
+ })
+ .catch((error) => {
+ console.error("ServiceWorker registration failed:", error);
+ });
+ });
+}