diff --git a/package-lock.json b/package-lock.json
index ca704df5..88451273 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -26,7 +26,8 @@
"react-icons": "^4.12.0",
"react-leaflet": "^4.2.1",
"react-responsive-carousel": "^3.2.23",
- "slick-carousel": "^1.8.1"
+ "slick-carousel": "^1.8.1",
+ "supabase": "^1.167.4"
},
"devDependencies": {
"@calblueprint/eslint-config-react": "^0.0.3",
@@ -224,7 +225,6 @@
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
- "dev": true,
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
@@ -241,7 +241,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
- "dev": true,
"engines": {
"node": ">=12"
},
@@ -253,7 +252,6 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
- "dev": true,
"dependencies": {
"ansi-regex": "^6.0.1"
},
@@ -264,6 +262,17 @@
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "dependencies": {
+ "minipass": "^7.0.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.3",
"dev": true,
@@ -538,7 +547,6 @@
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
- "dev": true,
"optional": true,
"engines": {
"node": ">=14"
@@ -973,6 +981,17 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
+ "node_modules/agent-base": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+ "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/ajv": {
"version": "6.12.6",
"dev": true,
@@ -1015,7 +1034,6 @@
},
"node_modules/ansi-regex": {
"version": "5.0.1",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -1023,7 +1041,6 @@
},
"node_modules/ansi-styles": {
"version": "4.3.0",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
@@ -1292,9 +1309,22 @@
},
"node_modules/balanced-match": {
"version": "1.0.2",
- "dev": true,
"license": "MIT"
},
+ "node_modules/bin-links": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.4.tgz",
+ "integrity": "sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA==",
+ "dependencies": {
+ "cmd-shim": "^6.0.0",
+ "npm-normalize-package-bin": "^3.0.0",
+ "read-cmd-shim": "^4.0.0",
+ "write-file-atomic": "^5.0.0"
+ },
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/binary-extensions": {
"version": "2.2.0",
"dev": true,
@@ -1503,6 +1533,14 @@
"node": ">= 6"
}
},
+ "node_modules/chownr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/classnames": {
"version": "2.3.2",
"license": "MIT"
@@ -1540,9 +1578,16 @@
"version": "0.0.1",
"license": "MIT"
},
+ "node_modules/cmd-shim": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.3.tgz",
+ "integrity": "sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA==",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
@@ -1553,7 +1598,6 @@
},
"node_modules/color-name": {
"version": "1.1.4",
- "dev": true,
"license": "MIT"
},
"node_modules/colord": {
@@ -1604,7 +1648,6 @@
},
"node_modules/cross-spawn": {
"version": "7.0.3",
- "dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
@@ -1675,9 +1718,16 @@
"dev": true,
"license": "BSD-2-Clause"
},
+ "node_modules/data-uri-to-buffer": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/debug": {
"version": "4.3.4",
- "dev": true,
"license": "MIT",
"dependencies": {
"ms": "2.1.2"
@@ -1781,7 +1831,6 @@
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
- "dev": true,
"license": "MIT"
},
"node_modules/electron-to-chromium": {
@@ -1792,7 +1841,6 @@
},
"node_modules/emoji-regex": {
"version": "9.2.2",
- "dev": true,
"license": "MIT"
},
"node_modules/enhanced-resolve": {
@@ -2575,6 +2623,28 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/fetch-blob": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "dependencies": {
+ "node-domexception": "^1.0.0",
+ "web-streams-polyfill": "^3.0.3"
+ },
+ "engines": {
+ "node": "^12.20 || >= 14.13"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"dev": true,
@@ -2661,7 +2731,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
"integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
- "dev": true,
"dependencies": {
"cross-spawn": "^7.0.0",
"signal-exit": "^4.0.1"
@@ -2677,7 +2746,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
- "dev": true,
"engines": {
"node": ">=14"
},
@@ -2697,6 +2765,17 @@
"node": ">= 6"
}
},
+ "node_modules/formdata-polyfill": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+ "dependencies": {
+ "fetch-blob": "^3.1.2"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
"node_modules/fraction.js": {
"version": "4.3.7",
"dev": true,
@@ -2985,6 +3064,18 @@
"version": "2.3.8",
"license": "Apache-2.0"
},
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
+ "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
+ "dependencies": {
+ "agent-base": "^7.0.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/human-signals": {
"version": "4.3.1",
"dev": true,
@@ -3040,7 +3131,6 @@
},
"node_modules/imurmurhash": {
"version": "0.1.4",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.8.19"
@@ -3427,7 +3517,6 @@
},
"node_modules/isexe": {
"version": "2.0.0",
- "dev": true,
"license": "ISC"
},
"node_modules/iterator.prototype": {
@@ -3468,6 +3557,12 @@
"jiti": "bin/jiti.js"
}
},
+ "node_modules/jquery": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
+ "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
+ "peer": true
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"license": "MIT"
@@ -3801,11 +3896,114 @@
}
},
"node_modules/minipass": {
- "version": "5.0.0",
- "dev": true,
- "license": "ISC",
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"engines": {
- "node": ">=8"
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz",
+ "integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==",
+ "dependencies": {
+ "minipass": "^7.0.4",
+ "rimraf": "^5.0.5"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/minizlib/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/minizlib/node_modules/glob": {
+ "version": "10.4.1",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz",
+ "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minizlib/node_modules/jackspeak": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz",
+ "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
+ "node_modules/minizlib/node_modules/minimatch": {
+ "version": "9.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
+ "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minizlib/node_modules/rimraf": {
+ "version": "5.0.7",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz",
+ "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==",
+ "dependencies": {
+ "glob": "^10.3.7"
+ },
+ "bin": {
+ "rimraf": "dist/esm/bin.mjs"
+ },
+ "engines": {
+ "node": ">=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
+ "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
+ "bin": {
+ "mkdirp": "dist/cjs/src/bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/moment": {
@@ -3818,7 +4016,6 @@
},
"node_modules/ms": {
"version": "2.1.2",
- "dev": true,
"license": "MIT"
},
"node_modules/mz": {
@@ -3957,6 +4154,41 @@
"resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.1.3.tgz",
"integrity": "sha512-opgw9iSCAzT2+6wJOETCpeRYAQxSopqQ2z+N6BXwIMsQQ7Zj5M8MaafQY8JMlolRR6R1UXg2WmhKp0p9lSOivg=="
},
+ "node_modules/node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "github",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "engines": {
+ "node": ">=10.5.0"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
+ "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
+ "dependencies": {
+ "data-uri-to-buffer": "^4.0.0",
+ "fetch-blob": "^3.1.4",
+ "formdata-polyfill": "^4.0.10"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/node-fetch"
+ }
+ },
"node_modules/node-gyp-build": {
"version": "4.7.0",
"license": "MIT",
@@ -3988,6 +4220,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/npm-normalize-package-bin": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz",
+ "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/npm-run-path": {
"version": "5.1.0",
"dev": true,
@@ -4224,7 +4464,6 @@
},
"node_modules/path-key": {
"version": "3.1.1",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -4236,16 +4475,15 @@
"license": "MIT"
},
"node_modules/path-scurry": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz",
- "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==",
- "dev": true,
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
"dependencies": {
"lru-cache": "^10.2.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
},
"engines": {
- "node": ">=16 || 14 >=14.17"
+ "node": ">=16 || 14 >=14.18"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -4255,7 +4493,6 @@
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
"integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==",
- "dev": true,
"engines": {
"node": "14 || >=16.14"
}
@@ -4649,6 +4886,14 @@
"pify": "^2.3.0"
}
},
+ "node_modules/read-cmd-shim": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz",
+ "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/readdirp": {
"version": "3.6.0",
"dev": true,
@@ -4898,7 +5143,6 @@
},
"node_modules/shebang-command": {
"version": "2.0.0",
- "dev": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
@@ -4909,7 +5153,6 @@
},
"node_modules/shebang-regex": {
"version": "3.0.0",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -5017,7 +5260,6 @@
},
"node_modules/string-width": {
"version": "5.1.2",
- "dev": true,
"license": "MIT",
"dependencies": {
"eastasianwidth": "^0.2.0",
@@ -5036,7 +5278,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -5049,21 +5290,18 @@
"node_modules/string-width-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/string-width/node_modules/ansi-regex": {
"version": "6.0.1",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -5074,7 +5312,6 @@
},
"node_modules/string-width/node_modules/strip-ansi": {
"version": "7.1.0",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
@@ -5149,7 +5386,6 @@
},
"node_modules/strip-ansi": {
"version": "6.0.1",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -5163,7 +5399,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -5270,6 +5505,24 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/supabase": {
+ "version": "1.167.4",
+ "resolved": "https://registry.npmjs.org/supabase/-/supabase-1.167.4.tgz",
+ "integrity": "sha512-DTaTsYQ48FdOPvTTl3H1cQnGDHvm4kQdBakeI5qbs7BFZgu2SRJDYRrCcSgH9sbZReOKrQdJCPfNpoy/Z359gA==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "bin-links": "^4.0.3",
+ "https-proxy-agent": "^7.0.2",
+ "node-fetch": "^3.3.2",
+ "tar": "7.1.0"
+ },
+ "bin": {
+ "supabase": "bin/supabase"
+ },
+ "engines": {
+ "npm": ">=8"
+ }
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"dev": true,
@@ -5337,6 +5590,30 @@
"node": ">=6"
}
},
+ "node_modules/tar": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.1.0.tgz",
+ "integrity": "sha512-ENhg4W6BmjYxl8GTaE7/h99f0aXiSWv4kikRZ9n2/JRxypZniE84ILZqimAhxxX7Zb8Px6pFdheW3EeHfhnXQQ==",
+ "dependencies": {
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.0",
+ "minizlib": "^3.0.1",
+ "mkdirp": "^3.0.1",
+ "yallist": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tar/node_modules/yallist": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/text-table": {
"version": "0.2.0",
"dev": true,
@@ -5613,6 +5890,14 @@
"loose-envify": "^1.0.0"
}
},
+ "node_modules/web-streams-polyfill": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
+ "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"license": "BSD-2-Clause"
@@ -5653,7 +5938,6 @@
},
"node_modules/which": {
"version": "2.0.2",
- "dev": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
@@ -5739,7 +6023,6 @@
},
"node_modules/wrap-ansi": {
"version": "8.1.0",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.1.0",
@@ -5758,7 +6041,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@@ -5774,14 +6056,12 @@
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -5790,7 +6070,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -5802,7 +6081,6 @@
},
"node_modules/wrap-ansi/node_modules/ansi-regex": {
"version": "6.0.1",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -5813,7 +6091,6 @@
},
"node_modules/wrap-ansi/node_modules/ansi-styles": {
"version": "6.2.1",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -5824,7 +6101,6 @@
},
"node_modules/wrap-ansi/node_modules/strip-ansi": {
"version": "7.1.0",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
@@ -5841,6 +6117,29 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/write-file-atomic": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
+ "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
+ "dependencies": {
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/write-file-atomic/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/yaeti": {
"version": "0.0.6",
"license": "MIT",
diff --git a/package.json b/package.json
index 6f86fe32..1d02397f 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,8 @@
"react-icons": "^4.12.0",
"react-leaflet": "^4.2.1",
"react-responsive-carousel": "^3.2.23",
- "slick-carousel": "^1.8.1"
+ "slick-carousel": "^1.8.1",
+ "supabase": "^1.167.4"
},
"devDependencies": {
"@calblueprint/eslint-config-react": "^0.0.3",
diff --git a/public/icons.tsx b/public/icons.tsx
index 29364f9d..01a027db 100644
--- a/public/icons.tsx
+++ b/public/icons.tsx
@@ -209,6 +209,28 @@ export function Congratulations() {
);
}
+/**
+ * @returns Left chevron for Carousel.
+ */
+export function LeftChevron() {
+ return (
+
+
+
+ );
+}
+
/**
* @returns Right chevron for Carousel.
*/
diff --git a/src/app/exhibitsPage/page.tsx b/src/app/exhibits/page.tsx
similarity index 97%
rename from src/app/exhibitsPage/page.tsx
rename to src/app/exhibits/page.tsx
index ab4de68d..bb7300ff 100644
--- a/src/app/exhibitsPage/page.tsx
+++ b/src/app/exhibits/page.tsx
@@ -2,7 +2,7 @@
import React, { useEffect, useState } from 'react';
import Link from 'next/link';
-import NavBar from '../../components/userComponents/navBar/navBar';
+import NavBar from '../../components/userComponents/NavBar/NavBar';
import { CategoryRow } from '../../types/types';
import { fetchAllCategories } from '../../supabase/category/queries';
import Exhibit from '../../components/userComponents/Exhibit/Exhibit';
@@ -65,7 +65,7 @@ function App() {
the QR codes on display for more information.
-
+
Go to Map
@@ -113,7 +113,7 @@ function App() {
the QR codes on display for more information.
-
+
Go to Map
diff --git a/src/app/featuredToursPage/[tourId]/page.tsx b/src/app/featuredToursPage/[tourId]/page.tsx
deleted file mode 100644
index dd1f5cbf..00000000
--- a/src/app/featuredToursPage/[tourId]/page.tsx
+++ /dev/null
@@ -1,137 +0,0 @@
-'use client';
-
-import React, { useEffect, useState } from 'react';
-import Image from 'next/image';
-import Link from 'next/link';
-
-import { fetchAllDisplays } from '../../../supabase/displays/queries';
-import { fetchMedia } from '../../../supabase/media/queries';
-import { fetchTour } from '../../../supabase/tours/queries';
-import { fetchTourDisplays } from '../../../supabase/tour_displays/queries';
-import { fetchTourMedia } from '../../../supabase/tour_media/queries';
-import {
- DisplayRow,
- MediaRow,
- TourDisplaysRow,
- TourMediaRow,
- TourRow,
-} from '../../../types/types';
-
-import BackButton from '../../../components/userComponents/BackButton/BackButton';
-import NavBar from '../../../components/userComponents/navBar/navBar';
-
-/**
- * @param params -
- * @param params.params -
- * @param params.params.tourId - The tour ID
- * @returns The tour start page
- */
-export default function TourStartPage({
- params,
-}: {
- params: { tourId: string };
-}) {
- const [tour, setTour] = useState();
- const [tourDisplays, setTourDisplays] = useState([]);
- const [displays, setDisplays] = useState([]);
- const [tourMedia, setTourMedia] = useState([]);
- const [media, setMedia] = useState([]);
-
- useEffect(() => {
- // Fetch tour, tour displays, and tour media data
- const fetchData = async () => {
- const fetchedTour = await fetchTour(params.tourId);
- setTour(fetchedTour);
- const fetchedTourDisplays = await fetchTourDisplays(params.tourId);
- setTourDisplays(fetchedTourDisplays);
- const fetchedDisplays = await fetchAllDisplays();
- setDisplays(fetchedDisplays);
- const fetchedTourMedia = await fetchTourMedia(params.tourId);
- setTourMedia(fetchedTourMedia);
- const fetchedMedia = await fetchMedia();
- setMedia(fetchedMedia);
- };
-
- fetchData();
- }, [params.tourId]);
-
- return (
- tour && (
-
-
-
-
-
-
- {media.length > 0 && (
- m.id === tourMedia[0]?.media_id)?.id}
- src={media.find(m => m.id === tourMedia[0]?.media_id)?.url ?? ''}
- alt={media.find(m => m.id === tourMedia[0]?.media_id)?.text ?? ''}
- layout="fill"
- objectFit="cover"
- priority
- />
- )}
-
-
-
-
-
-
- WELCOME TO
-
-
- {tour.name}
-
-
-
-
-
- Start Tour
-
-
-
-
-
-
{tour.description}
-
-
-
-
- In this tour
-
-
-
- {tour.stop_count} stops
-
-
-
-
- {tourDisplays.map(tourDisplay => (
-
-
- {tourDisplay.display_order != null
- ? tourDisplay.display_order + 1
- : ''}
- .{' '}
- {
- displays.find(
- display => display.id === tourDisplay.display_id,
- )?.title
- }
-
-
- ))}
-
-
-
-
- )
- );
-}
diff --git a/src/app/featuredToursPage/[tourId]/tourEndPage/page.tsx b/src/app/featuredToursPage/[tourId]/tourEndPage/page.tsx
deleted file mode 100644
index e514f030..00000000
--- a/src/app/featuredToursPage/[tourId]/tourEndPage/page.tsx
+++ /dev/null
@@ -1,142 +0,0 @@
-'use client';
-
-import Link from 'next/link';
-import React, { useEffect, useState } from 'react';
-
-import NavBar from '../../../../components/userComponents/navBar/navBar';
-import {
- MediaRow,
- TourRow,
- TourMediaRow,
- TourDisplaysRow,
-} from '../../../../types/types';
-import { fetchMedia } from '../../../../supabase/media/queries';
-import { fetchTour } from '../../../../supabase/tours/queries';
-import { fetchTourDisplays } from '../../../../supabase/tour_displays/queries';
-import { fetchTourMedia } from '../../../../supabase/tour_media/queries';
-import {
- BackArrow,
- Congratulations,
- ExternalLinkIcon,
-} from '../../../../../public/icons';
-
-/**
- * @param params -
- * @param params.params -
- * @param params.params.tourId - The tour ID
- * @returns The tour end page
- */
-export default function TourEndPage({
- params,
-}: {
- params: { tourId: string };
-}) {
- const [media, setMedia] = useState([]);
- const [tour, setTour] = useState();
- const [tourMedia, setTourMedia] = useState([]);
- const [backLink, setBackLink] = useState(
- `/featuredToursPage/${params.tourId}`,
- );
-
- useEffect(() => {
- // Get tour
- const getTour = async () => {
- const fetchedTour = await fetchTour(params.tourId);
- setTour(fetchedTour);
- };
-
- // Get tour media
- const getTourMedia = async () => {
- const fetchedTourMedia = await fetchTourMedia(params.tourId);
- setTourMedia(fetchedTourMedia);
- };
-
- // Get media
- const getMedia = async () => {
- const fetchedMedia = await fetchMedia();
- setMedia(fetchedMedia);
- };
-
- /**
- * @returns The link to the previous page.
- */
- async function getBackLink() {
- const tourDisplays: TourDisplaysRow[] = await fetchTourDisplays(
- params.tourId,
- );
- setBackLink(
- `/featuredToursPage/${params.tourId}/${
- tourDisplays[tourDisplays.length - 1].display_id
- }`,
- );
- }
-
- getTour();
- getTourMedia();
- getMedia();
- getBackLink();
- }, [params.tourId]);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- {`You've reached the end of this tour!`}
-
-
-
- Thanks for visiting {tour?.name}.
-
-
-
-
-
- Back to Virtual Tours
-
-
-
-
-
-
-
-
-
Related Links
-
- {tourMedia.map((tm, index) => (
-
- m.id === tm.media_id)?.url ?? '-1'}
- className="flex flex-col gap-1"
- >
-
-
- {media.find(m => m.id === tm.media_id)?.type}
-
-
-
-
- {media.find(m => m.id === tm.media_id)?.title}
-
-
- {index !== tourMedia.length - 1 && (
-
- )}
-
- ))}
-
-
-
-
-
-
- );
-}
diff --git a/src/app/featuredToursPage/page.tsx b/src/app/featuredToursPage/page.tsx
deleted file mode 100644
index 28b7ac88..00000000
--- a/src/app/featuredToursPage/page.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-'use client';
-
-import React, { useEffect, useState } from 'react';
-import Image from 'next/image';
-import Link from 'next/link';
-
-import { fetchAllTours } from '../../supabase/tours/queries';
-import { fetchMedia } from '../../supabase/media/queries';
-import { fetchAllTourMedia } from '../../supabase/tour_media/queries';
-import { TourRow, MediaRow, TourMediaRow } from '../../types/types';
-
-import { BackArrow } from '../../../public/icons';
-import NavBar from '../../components/userComponents/navBar/navBar';
-import NextButton from '../../components/userComponents/NextButton/NextButton';
-
-/**
- * @returns The featured tours page.
- */
-export default function FeaturedToursPage() {
- const [tours, setTours] = useState([]);
- const [allTourMedia, setAllTourMedia] = useState([]);
- const [media, setMedia] = useState([]);
-
- useEffect(() => {
- // Fetch tour and tour media data
- const fetchData = async () => {
- const fetchedTours = await fetchAllTours();
- setTours(fetchedTours);
- const fetchedAllTourMedia = await fetchAllTourMedia();
- setAllTourMedia(fetchedAllTourMedia);
- const fetchedMedia = await fetchMedia();
- setMedia(fetchedMedia);
- };
-
- fetchData();
- }, []);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
- Virtual Tours
-
-
- Take a virtual sneak peek behind the scenes at our Wildlife Care
- Center. Here you will find outside enclosures where sick, injured, and
- orphaned wildlife recuperate and acclimate before being released back
- into their natural habitat. Choose your favorite animal to start the
- tour.
-
-
-
- {tours.map(
- tour =>
- tour.spotlight === false && (
-
-
-
- {media.length > 0 && (
-
- m.id ===
- allTourMedia.find(tm => tm.tour_id === tour.id)
- ?.media_id,
- )?.url ?? ''
- }
- alt={
- media.find(
- m =>
- m.id ===
- allTourMedia.find(tm => tm.tour_id === tour.id)
- ?.media_id,
- )?.text ?? ''
- }
- layout="fill"
- objectFit="cover"
- priority
- />
- )}
-
-
- {tour.stop_count} stops
-
-
-
- {tour.name}
-
-
-
-
-
-
-
-
-
- ),
- )}
-
-
-
- );
-}
diff --git a/src/app/globals.css b/src/app/globals.css
index 49144bab..4855e7d0 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -22,43 +22,43 @@ These styles are applied automatically to certain div tags, but you can also cal
/* Mobile Text Styles */
.h1 {
/* Header 1 */
- @apply text-3xl leading-9 font-medium text-ivory font-lato;
+ @apply text-ivory font-lato text-[2rem] lg:text-[2.625rem] not-italic font-bold leading-[1.3];
}
.h2 {
/* Header 2 */
- @apply text-2xl leading-7 font-bold text-ivory font-lato;
+ @apply text-ivory font-lato text-[1.5rem] lg:text-[1.75rem] not-italic font-semibold leading-[1.3];
}
.h3 {
/* Header 3 */
- @apply text-xl leading-6 font-bold text-ivory font-lato;
+ @apply text-ivory font-lato text-[1.25rem] lg:text-[1.5rem] italic font-normal leading-[1.3];
}
.h4 {
/* Header 4 */
- @apply text-lg leading-5 text-base font-bold text-ivory font-lato;
+ @apply text-ivory font-lato text-[1.125rem] lg:text-[1.25rem] not-italic font-bold leading-[1.3];
}
.b1 {
/* Button */
- @apply text-base leading-5 font-semibold text-ivory font-lato;
+ @apply text-ivory font-lato text-[1rem] lg:text-[1.0625rem] not-italic font-bold leading-[1.5];
}
.b2 {
/* Bolded Body */
- @apply text-base leading-5 font-medium text-ivory font-lato;
+ @apply text-ivory font-lato text-[1rem] lg:text-[1.0625rem] not-italic font-medium leading-[1.3];
}
.b3 {
/* Body Text */
- @apply text-base leading-5 font-normal text-ivory font-lato;
+ @apply text-ivory font-lato text-[1rem] lg:text-[1.0625rem] not-italic font-normal leading-[1.3];
}
.s1 {
/* Subtitle Text */
- @apply text-sm leading-4 font-light text-ivory font-lato;
+ @apply text-ivory font-lato text-[0.875rem] lg:text-[0.9375rem] not-italic font-normal leading-[1.3];
}
.s2 {
/* Category Label Text */
- @apply text-xs font-normal text-ivory font-lato;
+ @apply text-ivory font-lato text-[0.75rem] lg:text-[0.8125rem] not-italic font-normal uppercase leading-[1.3];
}
.s3 {
/* Caption Text */
- @apply text-xs font-light text-ivory font-lato;
+ @apply text-ivory font-lato text-[0.75rem] lg:text-[0.8125rem] not-italic font-normal leading-[1.3];
}
}
/* Base layer: To match figma design system, certain styles are auto-applied to these HTML tags. You can overwrite them if needed.*/
diff --git a/src/app/hours-and-location/page.tsx b/src/app/hours-and-location/page.tsx
new file mode 100644
index 00000000..35e4ad07
--- /dev/null
+++ b/src/app/hours-and-location/page.tsx
@@ -0,0 +1,143 @@
+'use client';
+
+import React, { useEffect, useState } from 'react';
+import { FiCalendar, FiCompass } from 'react-icons/fi';
+import Link from 'next/link';
+import NavBar from '../../components/userComponents/NavBar/NavBar';
+import { BackArrow } from '../../../public/icons';
+
+/**
+ * @returns The hours and location page.
+ */
+export default function HoursLocationPage() {
+ const [isWide, setIsWide] = useState(false);
+
+ useEffect(() => {
+ if (window) {
+ setIsWide(window.innerWidth >= 1024);
+ }
+ // Update isWide state on window resize
+ const handleResize = () => setIsWide(window.innerWidth >= 1024);
+ window.addEventListener('resize', handleResize);
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ };
+ }, []);
+
+ return isWide ? (
+
+
+
+
+
+
+ Home / Hours & Location
+
+
Hours & Location
+
+
+
+
+
+
Site Information
+
+
+
+
+
+ 24103 Congress Springs Road,
+
+
+
Saratoga, CA 95070
+
+
+
+
+ Monday-Sunday | 9 AM to 6 PM
+
+
+
Closed on holidays*
+
+
+
+
Contact Us
+
+
+
Wildlife Care Center
+
650-340-7022
+
+
+
Peninsula Intake
+
650-340-7022
+
+
+
South Bay Intake
+
408-929-9453
+
+
+
+ If you’ve found a wild animal that appears to be sick,
+ injured, or orphaned, safely contain it and either bring it to
+ our nearest shelter or contact us for guidance.
+
+
+
+
+
+
+
+ ) : (
+
+
+
+
+
+
+
+
+
Hours & Location
+
Site Information
+
+
+
+
+
+
24103 Congress Springs Road,
+
+
Saratoga, CA 95070
+
+
+
+
Monday-Sunday | 9 AM to 6 PM
+
+
Closed on holidays*
+
+
+
Contact Us
+
+
+
Wildlife Care Center
+
650-340-7022
+
+
+
Peninsula Intake
+
650-340-7022
+
+
+
South Bay Intake
+
408-929-9453
+
+
+
+ If you’ve found a wild animal that appears to be sick, injured, or
+ orphaned, safely contain it and either bring it to our nearest shelter
+ or contact us for guidance.
+
+
+
+ );
+}
diff --git a/src/app/hoursAdmissionPage/page.tsx b/src/app/hoursAdmissionPage/page.tsx
deleted file mode 100644
index 2b686234..00000000
--- a/src/app/hoursAdmissionPage/page.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-'use client';
-
-import React from 'react';
-import { FiCalendar, FiCompass } from 'react-icons/fi';
-import Link from 'next/link';
-import NavBar from '../../components/userComponents/navBar/navBar';
-import { BackArrow } from '../../../public/icons';
-
-/**
- * @returns The hours and admission page.
- */
-export default function HoursAdmissionPage() {
- return (
-
-
-
-
-
-
-
-
-
- Hours & Location
-
-
- Site Information
-
-
-
-
-
-
- 24103 Congress Springs Road, Saratoga, CA 95070
-
-
-
-
-
- Monday-Sunday | 9 AM to 6 PM
-
-
-
- Closed on holidays*
-
-
-
-
- Contact Us
-
-
-
-
- Wildlife Care Center
-
-
650-340-7022
-
-
-
Peninsula Intake
-
650-340-7022
-
-
-
South Bay Intake
-
408-929-9453
-
-
-
- If you've found a wild animal that appears to be sick, injured, or
- orphaned, safely contain it and either bring it to our nearest shelter
- or contact us for guidance.
-
-
-
- );
-}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index b489d625..26300222 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,17 +1,18 @@
import './globals.css';
import type { Metadata } from 'next';
-import { Inter } from 'next/font/google';
+import { Inter, Lato } from 'next/font/google';
import React from 'react';
import { WindowWidthProvider } from '../context/WindowWidthContext/WindowWidthContext';
const inter = Inter({ subsets: ['latin'] });
-// const lato = Lato({ weight: ['300', '400', '500', '700'], subsets: ['latin'] });
+const lato = Lato({ weight: ['400', '700'], subsets: ['latin'] });
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
};
+
/**
* @param root0 - Destructured object containing the properties.
* @param root0.children - The child elements to be rendered within the RootLayout component.
@@ -44,10 +45,9 @@ export default function RootLayout({
crossOrigin=""
/>
-
-
+
{children}
diff --git a/src/app/newsFeedPage/page.tsx b/src/app/news/page.tsx
similarity index 97%
rename from src/app/newsFeedPage/page.tsx
rename to src/app/news/page.tsx
index afb2c4f5..3784940e 100644
--- a/src/app/newsFeedPage/page.tsx
+++ b/src/app/news/page.tsx
@@ -3,7 +3,7 @@
import React, { useEffect, useState } from 'react';
import Link from 'next/link';
import BackButton from '../../components/userComponents/BackButton/page';
-import NavBar from '../../components/userComponents/navBar/navBar';
+import NavBar from '../../components/userComponents/NavBar/NavBar';
import { NewsRow } from '../../types/types';
import { fetchAllNewsByDate } from '../../supabase/news/queries';
import NewsDisplay from '../../components/userComponents/NewsDisplay/NewsDisplay';
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 3fa71985..6a95efc1 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -2,7 +2,7 @@
import React from 'react';
import HomeWildlifeSpotlights from '../components/userComponents/HomePageComponents/HomeWildlifeSpotlights/HomeWildlifeSpotlights';
-import NavBar from '../components/userComponents/navBar/navBar';
+import NavBar from '../components/userComponents/NavBar/NavBar';
import VisitorResources from '../components/userComponents/HomePageComponents/VisitorResources/VisitorResources';
import WelcomeGraphic from '../components/userComponents/HomePageComponents/WelcomeGraphic/WelcomeGraphic';
import HomeVirtualTours from '../components/userComponents/HomePageComponents/HomeVirtualTours/HomeVirtualTours';
diff --git a/src/app/siteMapPage/page.tsx b/src/app/site-maps/page.tsx
similarity index 51%
rename from src/app/siteMapPage/page.tsx
rename to src/app/site-maps/page.tsx
index 84cbfc0f..10ffcd8b 100644
--- a/src/app/siteMapPage/page.tsx
+++ b/src/app/site-maps/page.tsx
@@ -2,14 +2,11 @@
import React, { useState } from 'react';
import dynamic from 'next/dynamic';
-import NavBar from '../../components/userComponents/navBar/navBar';
+import NavBar from '../../components/userComponents/NavBar/NavBar';
import FilterButton from '../../components/userComponents/FilterButton/FilterButton';
import { useWebDeviceDetection } from '../../context/WindowWidthContext/WindowWidthContext';
-const filterButtonContent: string[] = [
- 'Virtual Tour Map',
- 'Exhibits Map',
-];
+const filterButtonContent: string[] = ['Virtual Tour Map', 'Exhibits Map'];
const SiteMap = dynamic(
() => import('../../components/userComponents/SiteMap/SiteMap'),
@@ -24,17 +21,16 @@ type ModeState = 'tours' | 'exhibits';
* @returns Page for the interactive map
*/
function MapPage() {
-
const [selectedMap, setSelectedMap] = useState(filterButtonContent[0]); // "Virtual Tour Map" by default
const [mode, setMode] = useState('tours');
const isWebDevice = useWebDeviceDetection();
-
+
const handleFilter = (mapName: string) => {
setSelectedMap(mapName);
- if (mapName === "Virtual Tour Map") {
- setMode("tours");
- } else if (mapName === "Exhibits Map") {
- setMode("exhibits");
+ if (mapName === 'Virtual Tour Map') {
+ setMode('tours');
+ } else if (mapName === 'Exhibits Map') {
+ setMode('exhibits');
}
};
@@ -55,17 +51,15 @@ function MapPage() {
);
const renderFilterContainerWide = () => (
-
-
+
{filterButtonContent &&
filterButtonContent.map(text => (
- handleFilter(text)}
- isSelected={selectedMap === text}
+ handleFilter(text)}
+ isSelected={selectedMap === text}
/>
-
))}
@@ -74,44 +68,47 @@ function MapPage() {
return isWebDevice ? (
<>
-
+
-
-
-
- Home / Wildlife Care Center Maps
-
-
-
-
-
Wildlife Care Center Maps
-
-
- {renderFilterContainerWide()}
+
+
+ Home{' '}
+ / Wildlife Care Center Maps
+
+
+
+
+
+ Wildlife Care Center Maps
+
+
+
+ {renderFilterContainerWide()}
+
+
+
+
+
-
-
-
-
-
-
>
) : (
<>
-
-
-
-
Wildlife Care Center Maps
-
+
+
+
+
+ Wildlife Care Center Maps
+
+
- {renderFilterContainer()}
-
-
-
+ {renderFilterContainer()}
+
-
>
);
}
diff --git a/src/app/spotlightPage/[spotlightId]/[displayId]/page.tsx b/src/app/spotlightPage/[spotlightId]/[displayId]/page.tsx
deleted file mode 100644
index 023a7c85..00000000
--- a/src/app/spotlightPage/[spotlightId]/[displayId]/page.tsx
+++ /dev/null
@@ -1,163 +0,0 @@
-'use client';
-
-import Link from 'next/link';
-import React, { useEffect, useState } from 'react';
-
-import { DisplayRow, MediaRow, TourMediaRow } from '../../../../types/types';
-import NavBar from '../../../../components/userComponents/navBar/navBar';
-import { fetchDisplayFromId } from '../../../../supabase/displays/queries';
-import { fetchDisplayfromSpotlight } from '../../../../supabase/tour_displays/queries';
-import BackButton from '../../../../components/userComponents/BackButton/BackButton';
-import Carousel from '../../../../components/userComponents/ImageScroller/ImageScroller';
-import { fetchImagesForDisplay } from '../../../../supabase/media/queries';
-import { ExternalLinkIcon } from '../../../../../public/icons';
-import { fetchTourMedia } from '../../../../supabase/tour_media/queries';
-
-/**
- * @param root0 -
- * @param root0.params -
- * @param root0.params.displayId - The display ID
- * @param root0.params.spotlightId - The spotlight ID
- * @returns display page
- */
-export default function Page({
- params,
-}: {
- params: { displayId: string; spotlightId: string };
-}) {
- const [display, setDisplay] = useState
([]);
- const [otherDisplays, setOtherDisplays] = useState([]);
- const [media, setMedia] = useState([]);
- const [tourMedia, setTourMedia] = useState([]);
-
- useEffect(() => {
- /**
- * @returns a display
- */
- async function fetchData() {
- try {
- const currentDisplayData: DisplayRow = await fetchDisplayFromId(
- params.displayId,
- );
- setDisplay(currentDisplayData);
-
- const displaysFromSpotlight: DisplayRow[] =
- await fetchDisplayfromSpotlight(params.spotlightId);
- const currentDisplayId = params.displayId;
- const responseDataOtherDisplays = displaysFromSpotlight.filter(
- aDisplay => aDisplay.id !== currentDisplayId,
- );
-
- setOtherDisplays(responseDataOtherDisplays);
- } catch (error) {
- console.error(error);
- }
- }
-
- // Get tour media
- const getTourMedia = async () => {
- const fetchedTourMedia = await fetchTourMedia(params.spotlightId);
- setTourMedia(fetchedTourMedia);
- };
-
- // Fetch the display media
- const fetchDisplayMedia = async () => {
- const displayMedia = await fetchImagesForDisplay(params.displayId);
- setMedia(displayMedia || []);
- };
-
- fetchData();
- getTourMedia();
- fetchDisplayMedia();
- }, []);
-
- return (
-
-
-
-
-
-
- {media.length > 0 ? (
-
- ) : (
-
- )}
-
-
- {display.title}
-
-
- {display.description}
-
-
- {otherDisplays.length > 0 && (
-
-
- More in this spotlight...
-
-
-
- {otherDisplays.map(otherDisplay => (
-
-
- {otherDisplay.title}
-
-
- ))}
-
-
- )}
-
- {tourMedia.length > 0 && (
-
-
-
-
-
- Related Links
-
-
- {tourMedia.map((tm, index) => (
-
- m.id === tm.media_id)?.url ?? '-1'}
- className="flex flex-col gap-1"
- >
-
-
- {media.find(m => m.id === tm.media_id)?.type}
-
-
-
-
- {media.find(m => m.id === tm.media_id)?.title}
-
-
- {index !== tourMedia.length - 1 && (
-
- )}
-
- ))}
-
-
-
-
-
- )}
-
-
- See all spotlights
-
-
- );
-}
diff --git a/src/app/spotlightPage/[spotlightId]/page.tsx b/src/app/spotlightPage/[spotlightId]/page.tsx
deleted file mode 100644
index ea662b15..00000000
--- a/src/app/spotlightPage/[spotlightId]/page.tsx
+++ /dev/null
@@ -1,203 +0,0 @@
-'use client';
-
-import Link from 'next/link';
-import Image from 'next/image';
-import React, { useEffect, useState } from 'react';
-
-import {
- TourRow,
- DisplayRow,
- MediaRow,
- TourMediaRow,
-} from '../../../types/types';
-import { fetchTour } from '../../../supabase/tours/queries';
-import { fetchMedia } from '../../../supabase/media/queries';
-import {
- fetchAllTourMedia,
- fetchTourMedia,
-} from '../../../supabase/tour_media/queries';
-import NavBar from '../../../components/userComponents/navBar/navBar';
-import {
- fetchDisplayfromSpotlight,
- fetchRelatedSpotlightsfromSpotlightId,
-} from '../../../supabase/tour_displays/queries';
-import BackButton from '../../../components/userComponents/BackButton/BackButton';
-
-/**
- * @param params -
- * @param params.params -
- * @param params.params.spotlightId -
- * @returns a spotlight page given a spotlight Id
- */
-export default function Page({ params }: { params: { spotlightId: string } }) {
- const [spotlight, setSpotlight] = useState([]);
- const [displays, setDisplays] = useState([]);
- const [media, setMedia] = useState([]);
- const [tourMedia, setTourMedia] = useState([]);
- const [allTourMedia, setAllTourMedia] = useState([]);
- const [relatedSpotlights, setRelatedSpotlights] = useState([]);
-
- useEffect(() => {
- /**
- * @returns data from tour table and display table
- */
- async function fetchData() {
- const responseDataForSpotlight: TourRow = await fetchTour(
- params.spotlightId,
- );
- setSpotlight(responseDataForSpotlight);
-
- const responseDataForDisplays: DisplayRow[] =
- await fetchDisplayfromSpotlight(params.spotlightId);
- setDisplays(responseDataForDisplays);
-
- const responseDataForRelatedSpotlights: TourRow[] =
- await fetchRelatedSpotlightsfromSpotlightId(params.spotlightId);
- setRelatedSpotlights(responseDataForRelatedSpotlights);
- }
-
- // Get tour media
- const getTourMedia = async () => {
- const fetchedTourMedia = await fetchTourMedia(params.spotlightId);
- setTourMedia(fetchedTourMedia);
- };
-
- // Get all tour media
- const getAllTourMedia = async () => {
- const fetchedAllTourMedia = await fetchAllTourMedia();
- setAllTourMedia(fetchedAllTourMedia);
- };
-
- // Get media
- const getMedia = async () => {
- const fetchedMedia = await fetchMedia();
- setMedia(fetchedMedia);
- };
-
- fetchData();
- getTourMedia();
- getMedia();
- getAllTourMedia();
- }, []);
-
- return (
-
-
-
-
-
-
- {media.length > 0 && (
- m.id === tourMedia[0]?.media_id)?.id}
- src={media.find(m => m.id === tourMedia[0]?.media_id)?.url ?? ''}
- alt={media.find(m => m.id === tourMedia[0]?.media_id)?.text ?? ''}
- layout="fill"
- objectFit="cover"
- priority
- />
- )}
-
-
-
- {spotlight.name}
-
-
- {spotlight.description}
-
-
-
- {displays.length > 0 && (
-
-
- In this spotlight...
-
-
-
- {displays.map(display => (
-
-
- {display.title}
-
-
- ))}
-
-
- )}
-
- {relatedSpotlights.length > 0 && (
-
-
-
-
-
- Related Spotlights
-
-
-
- {relatedSpotlights.map(otherSpotlight => (
-
-
-
- {media.length > 0 && (
-
- m.id ===
- allTourMedia.find(
- tm => tm.tour_id === otherSpotlight.id,
- )?.media_id,
- )?.id
- }
- src={
- media.find(
- m =>
- m.id ===
- allTourMedia.find(
- tm => tm.tour_id === otherSpotlight.id,
- )?.media_id,
- )?.url ?? ''
- }
- alt={
- media.find(
- m =>
- m.id ===
- allTourMedia.find(
- tm => tm.tour_id === otherSpotlight.id,
- )?.media_id,
- )?.text ?? ''
- }
- layout="fill"
- objectFit="cover"
- priority
- />
- )}
-
-
- {otherSpotlight.name}
-
-
- {otherSpotlight.preview_text}
-
-
-
- ))}
-
-
-
- )}
-
- );
-}
diff --git a/src/app/spotlightPage/page.tsx b/src/app/spotlightPage/page.tsx
deleted file mode 100644
index 2828023d..00000000
--- a/src/app/spotlightPage/page.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-'use client';
-
-import Link from 'next/link';
-import React, { useEffect, useState } from 'react';
-import Image from 'next/image';
-
-import { fetchAllSpotlights } from '../../supabase/tours/queries';
-import { fetchMedia } from '../../supabase/media/queries';
-import { fetchAllTourMedia } from '../../supabase/tour_media/queries';
-import NavBar from '../../components/userComponents/navBar/navBar';
-import { TourRow, MediaRow, TourMediaRow } from '../../types/types';
-import { BackArrow } from '../../../public/icons';
-
-/**
- * @returns spotlights from tours table
- */
-function App() {
- const [spotlights, setSpotlights] = useState([]);
- const [media, setMedia] = useState([]);
- const [allTourMedia, setAllTourMedia] = useState([]);
-
- useEffect(() => {
- /**
- * @returns spotlight data
- */
- async function fetchData() {
- try {
- const responseData: TourRow[] = await fetchAllSpotlights();
- setSpotlights(responseData);
- } catch (error) {
- console.error(error);
- }
- }
-
- // Get all tour media
- const getAllTourMedia = async () => {
- const fetchedAllTourMedia = await fetchAllTourMedia();
- setAllTourMedia(fetchedAllTourMedia);
- };
-
- // Get media
- const getMedia = async () => {
- const fetchedMedia = await fetchMedia();
- setMedia(fetchedMedia);
- };
-
- fetchData();
- getAllTourMedia();
- getMedia();
- }, []);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
- Our Wildlife Spotlights
-
-
- Wildlife Spotlights offer insights into common questions we receive.
- Browse a Spotlight to learn more about important wildlife topics.
-
-
-
-
- {spotlights.map(spotlight => (
-
-
-
- {media.length > 0 && (
-
- mediaElement.id ===
- allTourMedia.find(allTourMediaElement => allTourMediaElement.tour_id === spotlight.id)
- ?.media_id,
- )?.id
- }
- src={
- media.find(
- mediaElement =>
- mediaElement.id ===
- allTourMedia.find(allTourMediaElement => allTourMediaElement.tour_id === spotlight.id)
- ?.media_id,
- )?.url ?? ''
- }
- alt={
- media.find(
- mediaElement =>
- mediaElement.id ===
- allTourMedia.find(allTourMediaElement => allTourMediaElement.tour_id === spotlight.id)
- ?.media_id,
- )?.text ?? ''
- }
- layout="fill"
- objectFit="cover"
- priority
- />
- )}
-
-
- {spotlight.name}
-
-
- {spotlight.preview_text}
-
-
-
- ))}
-
-
-
- );
-}
-
-export default App;
diff --git a/src/app/featuredToursPage/[tourId]/[displayId]/page.tsx b/src/app/virtual-tours/[tourId]/[displayId]/page.tsx
similarity index 53%
rename from src/app/featuredToursPage/[tourId]/[displayId]/page.tsx
rename to src/app/virtual-tours/[tourId]/[displayId]/page.tsx
index ac14e648..c4f7c070 100644
--- a/src/app/featuredToursPage/[tourId]/[displayId]/page.tsx
+++ b/src/app/virtual-tours/[tourId]/[displayId]/page.tsx
@@ -9,7 +9,7 @@ import {
TourDisplaysRow,
MediaRow,
} from '../../../../types/types';
-import NavBar from '../../../../components/userComponents/navBar/navBar';
+import NavBar from '../../../../components/userComponents/NavBar/NavBar';
import { fetchTour } from '../../../../supabase/tours/queries';
import { fetchDisplay } from '../../../../supabase/displays/queries';
import { fetchTourDisplays } from '../../../../supabase/tour_displays/queries';
@@ -18,6 +18,7 @@ import LastStopButton from '../../../../components/userComponents/LastStopButton
import NextStopButton from '../../../../components/userComponents/NextStopButton/NextStopButton';
import { fetchImagesForDisplay } from '../../../../supabase/media/queries';
import Carousel from '../../../../components/userComponents/ImageScroller/ImageScroller';
+import TextButton from '../../../../components/userComponents/TextButton/TextButton';
/**
* Displays a stop page for the current tour
@@ -36,14 +37,13 @@ export default function TourStopPage({
const [tour, setTour] = useState();
const [currentStop, setCurrentStop] = useState();
const [media, setMedia] = useState([]);
- const [prev, setPrev] = useState(
- `/featuredToursPage/${params.tourId}`,
- );
+ const [prev, setPrev] = useState(`/virtual-tours/${params.tourId}`);
const [prevText, setPrevText] = useState('Back');
const [next, setNext] = useState(
- `/featuredToursPage/${params.tourId}/tourEndPage`,
+ `/virtual-tours/${params.tourId}/tour-end`,
);
const [nextText, setNextText] = useState('End Tour');
+ const [isWide, setIsWide] = useState(false);
useEffect(() => {
// Get display
@@ -75,27 +75,27 @@ export default function TourStopPage({
throw new Error('Display not found in tour displays');
} else if (index === 0) {
setNext(
- `/featuredToursPage/${params.tourId}/${
+ `/virtual-tours/${params.tourId}/${
tourDisplays[index + 1].display_id
}`,
);
setNextText('Next Stop');
} else if (index === tourDisplays.length - 1) {
setPrev(
- `/featuredToursPage/${params.tourId}/${
+ `/virtual-tours/${params.tourId}/${
tourDisplays[index - 1].display_id
}`,
);
setPrevText('Last Stop');
} else {
setPrev(
- `/featuredToursPage/${params.tourId}/${
+ `/virtual-tours/${params.tourId}/${
tourDisplays[index - 1].display_id
}`,
);
setPrevText('Last Stop');
setNext(
- `/featuredToursPage/${params.tourId}/${
+ `/virtual-tours/${params.tourId}/${
tourDisplays[index + 1].display_id
}`,
);
@@ -133,37 +133,84 @@ export default function TourStopPage({
fetchDisplayMedia();
}, [params.displayId, params.tourId]);
- return (
-
+ useEffect(() => {
+ if (window) {
+ setIsWide(window.innerWidth >= 1024);
+ }
+ // Update isWide state on window resize
+ const handleResize = () => setIsWide(window.innerWidth >= 1024);
+ window.addEventListener('resize', handleResize);
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ };
+ }, []);
+
+ return isWide ? (
+
- {(currentStop && tour?.stop_count) > 0 && (
-
- )}
-
- {media.length > 0 ? (
-
- ) : (
-
- )}
+
+
+
+
{display && display.title}
+
+ {media.length > 0 && }
+
+
+
+ {currentStop && tour?.stop_count && (
+
+ )}
+
+
+ {display && display.description}
+
+
+
+
+
+
+
+
+
+
+
-
- {display && display.title}
-
-
-
- {display && display.description}
-
-
-
-
+
+ ) : (
+
+
+
+
+ {currentStop && tour?.stop_count && (
+
+ )}
+
+
+ {media.length > 0 && }
+
+
+
+
{display && display.title}
+
+
{display && display.description}
+
+
+
+
+
+
+
+
+
-
- Exit this tour
-
);
diff --git a/src/app/virtual-tours/[tourId]/page.tsx b/src/app/virtual-tours/[tourId]/page.tsx
new file mode 100644
index 00000000..471b1449
--- /dev/null
+++ b/src/app/virtual-tours/[tourId]/page.tsx
@@ -0,0 +1,213 @@
+'use client';
+
+import React, { useEffect, useState } from 'react';
+import Link from 'next/link';
+
+import { fetchAllDisplays } from '../../../supabase/displays/queries';
+import { fetchMedia } from '../../../supabase/media/queries';
+import { fetchTour } from '../../../supabase/tours/queries';
+import { fetchTourDisplays } from '../../../supabase/tour_displays/queries';
+import { fetchTourMedia } from '../../../supabase/tour_media/queries';
+import {
+ DisplayRow,
+ MediaRow,
+ TourDisplaysRow,
+ TourMediaRow,
+ TourRow,
+} from '../../../types/types';
+
+import BackButton from '../../../components/userComponents/BackButton/BackButton';
+import NavBar from '../../../components/userComponents/NavBar/NavBar';
+import ButtonWithText from '../../../components/userComponents/ButtonWithText/ButtonWithText';
+
+/**
+ * @param params -
+ * @param params.params -
+ * @param params.params.tourId - The tour ID
+ * @returns The tour start page
+ */
+export default function TourStartPage({
+ params,
+}: {
+ params: { tourId: string };
+}) {
+ const [tour, setTour] = useState
();
+ const [tourDisplays, setTourDisplays] = useState([]);
+ const [displays, setDisplays] = useState([]);
+ const [tourMedia, setTourMedia] = useState([]);
+ const [media, setMedia] = useState([]);
+ const [isWide, setIsWide] = useState(false);
+
+ useEffect(() => {
+ // Fetch tour, tour displays, and tour media data
+ const fetchData = async () => {
+ const fetchedTour = await fetchTour(params.tourId);
+ setTour(fetchedTour);
+ const fetchedTourDisplays = await fetchTourDisplays(params.tourId);
+ setTourDisplays(fetchedTourDisplays);
+ const fetchedDisplays = await fetchAllDisplays();
+ setDisplays(fetchedDisplays);
+ const fetchedTourMedia = await fetchTourMedia(params.tourId);
+ setTourMedia(fetchedTourMedia);
+ const fetchedMedia = await fetchMedia();
+ setMedia(fetchedMedia);
+ };
+
+ fetchData();
+ }, [params.tourId]);
+
+ useEffect(() => {
+ if (window) {
+ setIsWide(window.innerWidth >= 1024);
+ }
+ // Update isWide state on window resize
+ const handleResize = () => setIsWide(window.innerWidth >= 1024);
+ window.addEventListener('resize', handleResize);
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ };
+ }, []);
+
+ return isWide
+ ? tour && (
+
+
+
+
+
+ {media.length > 0 && (
+
m.id === tourMedia[0]?.media_id)?.id}
+ src={
+ media.find(m => m.id === tourMedia[0]?.media_id)?.url ??
+ ''
+ }
+ alt={
+ media.find(m => m.id === tourMedia[0]?.media_id)?.text ??
+ ''
+ }
+ className="object-cover w-full h-full"
+ />
+ )}
+
+
+
+
+
WELCOME TO
+
{tour.name}
+
+
+
+
+
+
+
In this tour
+
+
{tour.stop_count} stops
+
+
+
+ {tourDisplays.map(tourDisplay => (
+
+
+ {tourDisplay.display_order != null
+ ? tourDisplay.display_order + 1
+ : ''}
+ .{' '}
+ {
+ displays.find(
+ display => display.id === tourDisplay.display_id,
+ )?.title
+ }
+
+
+ ))}
+
+
+
+
+
+
+ )
+ : tour && (
+
+
+
+
+
+
+
+ {media.length > 0 && (
+
m.id === tourMedia[0]?.media_id)?.id}
+ src={
+ media.find(m => m.id === tourMedia[0]?.media_id)?.url ?? ''
+ }
+ alt={
+ media.find(m => m.id === tourMedia[0]?.media_id)?.text ?? ''
+ }
+ className="object-cover w-full h-full"
+ />
+ )}
+
+
+
+
+
+
WELCOME TO
+
{tour.name}
+
+
+
+
+
+
+
+
+
+
+
In this tour
+
+
{tour.stop_count} stops
+
+
+
+ {tourDisplays.map(tourDisplay => (
+
+
+ {tourDisplay.display_order != null
+ ? tourDisplay.display_order + 1
+ : ''}
+ .{' '}
+ {
+ displays.find(
+ display => display.id === tourDisplay.display_id,
+ )?.title
+ }
+
+
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/src/app/virtual-tours/[tourId]/tour-end/page.tsx b/src/app/virtual-tours/[tourId]/tour-end/page.tsx
new file mode 100644
index 00000000..21507c62
--- /dev/null
+++ b/src/app/virtual-tours/[tourId]/tour-end/page.tsx
@@ -0,0 +1,119 @@
+'use client';
+
+import Link from 'next/link';
+import React, { useEffect, useState } from 'react';
+
+import NavBar from '../../../../components/userComponents/NavBar/NavBar';
+import { TourRow, TourDisplaysRow } from '../../../../types/types';
+import { fetchTour } from '../../../../supabase/tours/queries';
+import { fetchTourDisplays } from '../../../../supabase/tour_displays/queries';
+import { BackArrow, Congratulations } from '../../../../../public/icons';
+import ButtonWithText from '../../../../components/userComponents/ButtonWithText/ButtonWithText';
+import RelatedLinks from '../../../../components/userComponents/RelatedLinks/RelatedLinks';
+
+/**
+ * @param params -
+ * @param params.params -
+ * @param params.params.tourId - The tour ID
+ * @returns The tour end page
+ */
+export default function TourEndPage({
+ params,
+}: {
+ params: { tourId: string };
+}) {
+ const [tour, setTour] = useState();
+ const [backLink, setBackLink] = useState(
+ `/virtual-tours/${params.tourId}`,
+ );
+ const [isWide, setIsWide] = useState(false);
+
+ useEffect(() => {
+ // Fetch tour and back link data
+ const fetchData = async () => {
+ const fetchedTour = await fetchTour(params.tourId);
+ setTour(fetchedTour);
+ const tourDisplays: TourDisplaysRow[] = await fetchTourDisplays(
+ params.tourId,
+ );
+ setBackLink(
+ `/virtual-tours/${params.tourId}/${
+ tourDisplays[tourDisplays.length - 1].display_id
+ }`,
+ );
+ };
+
+ fetchData();
+ }, [params.tourId]);
+
+ useEffect(() => {
+ if (window) {
+ setIsWide(window.innerWidth >= 1024);
+ }
+ // Update isWide state on window resize
+ const handleResize = () => setIsWide(window.innerWidth >= 1024);
+ window.addEventListener('resize', handleResize);
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ };
+ }, []);
+
+ return isWide ? (
+
+
+
+
+
+
+
+
+
+ You’ve reached the end of this tour!
+
+
+
Thanks for visiting {tour?.name}.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ) : (
+
+
+
+
+
+
+
+
+
+
+
+
+ You’ve reached the end of this tour!
+
+
+
Thanks for visiting {tour?.name}.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/virtual-tours/page.tsx b/src/app/virtual-tours/page.tsx
new file mode 100644
index 00000000..272424ac
--- /dev/null
+++ b/src/app/virtual-tours/page.tsx
@@ -0,0 +1,210 @@
+'use client';
+
+import React, { useEffect, useState } from 'react';
+import Link from 'next/link';
+
+import { fetchAllTours } from '../../supabase/tours/queries';
+import { fetchMedia } from '../../supabase/media/queries';
+import { fetchAllTourMedia } from '../../supabase/tour_media/queries';
+import { TourRow, MediaRow, TourMediaRow } from '../../types/types';
+
+import { BackArrow } from '../../../public/icons';
+import NavBar from '../../components/userComponents/NavBar/NavBar';
+import NextButton from '../../components/userComponents/NextButton/NextButton';
+
+/**
+ * @returns The virtual tours page.
+ */
+export default function VirtualToursPage() {
+ const [tours, setTours] = useState([]);
+ const [allTourMedia, setAllTourMedia] = useState([]);
+ const [media, setMedia] = useState([]);
+ const [isWide, setIsWide] = useState(false);
+
+ useEffect(() => {
+ // Fetch tour and tour media data
+ const fetchData = async () => {
+ const fetchedTours = await fetchAllTours();
+ setTours(fetchedTours);
+ const fetchedAllTourMedia = await fetchAllTourMedia();
+ setAllTourMedia(fetchedAllTourMedia);
+ const fetchedMedia = await fetchMedia();
+ setMedia(fetchedMedia);
+ };
+
+ fetchData();
+ }, []);
+
+ useEffect(() => {
+ if (window) {
+ setIsWide(window.innerWidth >= 1024);
+ }
+ // Update isWide state on window resize
+ const handleResize = () => setIsWide(window.innerWidth >= 1024);
+ window.addEventListener('resize', handleResize);
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ };
+ }, []);
+
+ return (
+
+
+
+ {isWide ? (
+
+
+
+
+ Home / Virtual Tours
+
+
Virtual Tours
+
+ Take a virtual sneak peek behind the scenes at our Wildlife Care
+ Center. Here you will find outside enclosures where sick,
+ injured, and orphaned wildlife recuperate and acclimate before
+ being released back into their natural habitat. Choose your
+ favorite animal to start the tour.
+
+
+
+
+
+ {tours.map(
+ tour =>
+ tour.spotlight === false && (
+
+
+
+ {media.length > 0 && (
+
+ m.id ===
+ allTourMedia.find(
+ tm => tm.tour_id === tour.id,
+ )?.media_id,
+ )?.url ?? ''
+ }
+ alt={
+ media.find(
+ m =>
+ m.id ===
+ allTourMedia.find(
+ tm => tm.tour_id === tour.id,
+ )?.media_id,
+ )?.text ?? ''
+ }
+ className="object-cover w-full h-full"
+ />
+ )}
+
+
+ {tour.stop_count} stops
+
+
+
+ {tour.name}
+
+
+
+
+
+
+ ),
+ )}
+
+
+
+ ) : (
+
+
+
+
+
+
+
+
+
Virtual Tours
+
+ Take a virtual sneak peek behind the scenes at our Wildlife Care
+ Center. Here you will find outside enclosures where sick, injured,
+ and orphaned wildlife recuperate and acclimate before being
+ released back into their natural habitat. Choose your favorite
+ animal to start the tour.
+
+
+
+ {tours.map(
+ tour =>
+ tour.spotlight === false && (
+
+
+
+ {media.length > 0 && (
+
+ m.id ===
+ allTourMedia.find(
+ tm => tm.tour_id === tour.id,
+ )?.media_id,
+ )?.url ?? ''
+ }
+ alt={
+ media.find(
+ m =>
+ m.id ===
+ allTourMedia.find(
+ tm => tm.tour_id === tour.id,
+ )?.media_id,
+ )?.text ?? ''
+ }
+ className="object-cover w-full h-full"
+ />
+ )}
+
+
+ {tour.stop_count} stops
+
+
+
+ {tour.name}
+
+
+
+
+
+
+
+
+
+ ),
+ )}
+
+
+
+ )}
+
+ );
+}
diff --git a/src/app/wildlife-spotlights/[spotlightId]/[displayId]/page.tsx b/src/app/wildlife-spotlights/[spotlightId]/[displayId]/page.tsx
new file mode 100644
index 00000000..2bcec5ac
--- /dev/null
+++ b/src/app/wildlife-spotlights/[spotlightId]/[displayId]/page.tsx
@@ -0,0 +1,166 @@
+'use client';
+
+import Link from 'next/link';
+import React, { useEffect, useState } from 'react';
+
+import { DisplayRow, MediaRow, TourRow } from '../../../../types/types';
+import NavBar from '../../../../components/userComponents/NavBar/NavBar';
+import { fetchDisplayFromId } from '../../../../supabase/displays/queries';
+import { fetchTour } from '../../../../supabase/tours/queries';
+import { fetchDisplayfromSpotlight } from '../../../../supabase/tour_displays/queries';
+import BackButton from '../../../../components/userComponents/BackButton/BackButton';
+import Carousel from '../../../../components/userComponents/ImageScroller/ImageScroller';
+import { fetchImagesForDisplay } from '../../../../supabase/media/queries';
+import SpotlightDisplayButton from '../../../../components/userComponents/SpotlightDisplayButton/SpotlightDisplayButton';
+import TextButton from '../../../../components/userComponents/TextButton/TextButton';
+
+/**
+ * @param root0 -
+ * @param root0.params -
+ * @param root0.params.displayId - The display ID
+ * @param root0.params.spotlightId - The spotlight ID
+ * @returns display page
+ */
+export default function Page({
+ params,
+}: {
+ params: { displayId: string; spotlightId: string };
+}) {
+ const [display, setDisplay] = useState();
+ const [otherDisplays, setOtherDisplays] = useState([]);
+ const [media, setMedia] = useState([]);
+ const [spotlight, setSpotlight] = useState();
+ const [isWide, setIsWide] = useState(false);
+
+ useEffect(() => {
+ /**
+ * @returns a display
+ */
+ async function fetchData() {
+ const currentDisplayData: DisplayRow = await fetchDisplayFromId(
+ params.displayId,
+ );
+ setDisplay(currentDisplayData);
+
+ const displaysFromSpotlight: DisplayRow[] =
+ await fetchDisplayfromSpotlight(params.spotlightId);
+ const currentDisplayId = params.displayId;
+ const responseDataOtherDisplays = displaysFromSpotlight.filter(
+ aDisplay => aDisplay.id !== currentDisplayId,
+ );
+
+ setOtherDisplays(responseDataOtherDisplays);
+ const responseDataForSpotlight: TourRow = await fetchTour(
+ params.spotlightId,
+ );
+ setSpotlight(responseDataForSpotlight);
+ }
+
+ // Fetch the display media
+ const fetchDisplayMedia = async () => {
+ const displayMedia = await fetchImagesForDisplay(params.displayId);
+ setMedia(displayMedia || []);
+ };
+
+ fetchData();
+ fetchDisplayMedia();
+ }, [params.displayId, params.spotlightId]);
+
+ useEffect(() => {
+ if (window) {
+ setIsWide(window.innerWidth >= 1024);
+ }
+ // Update isWide state on window resize
+ const handleResize = () => setIsWide(window.innerWidth >= 1024);
+ window.addEventListener('resize', handleResize);
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ };
+ }, []);
+
+ return isWide ? (
+
+
+
+
+
+
{spotlight?.name}
+
{display?.title}
+
+
+
+
+ {media.length > 0 && }
+
+
{display?.description}
+
+ {otherDisplays.length > 0 && (
+
+
More in this spotlight...
+
+ {otherDisplays.map(otherDisplay => (
+
+
+
+
+
+ ))}
+
+
+
+
+
+ )}
+
+
+
+
+ ) : (
+
+
+
+
+
+
+ {media.length > 0 && }
+
+
+
+
+
{spotlight?.name}
+
{display?.title}
+
+
{display?.description}
+
+
+ {otherDisplays.length > 0 && (
+
+
More in this spotlight...
+
+
+ {otherDisplays.map(otherDisplay => (
+
+
+
+
+
+ ))}
+
+
+ )}
+
+
+
+
+
+ );
+}
diff --git a/src/app/wildlife-spotlights/[spotlightId]/page.tsx b/src/app/wildlife-spotlights/[spotlightId]/page.tsx
new file mode 100644
index 00000000..c0b9268b
--- /dev/null
+++ b/src/app/wildlife-spotlights/[spotlightId]/page.tsx
@@ -0,0 +1,335 @@
+'use client';
+
+import Link from 'next/link';
+import React, { useEffect, useState } from 'react';
+
+import {
+ TourRow,
+ DisplayRow,
+ MediaRow,
+ TourMediaRow,
+} from '../../../types/types';
+import { fetchTour } from '../../../supabase/tours/queries';
+import { fetchMedia } from '../../../supabase/media/queries';
+import {
+ fetchAllTourMedia,
+ fetchTourMedia,
+} from '../../../supabase/tour_media/queries';
+import NavBar from '../../../components/userComponents/NavBar/NavBar';
+import {
+ fetchDisplayfromSpotlight,
+ fetchRelatedSpotlightsfromSpotlightId,
+} from '../../../supabase/tour_displays/queries';
+import BackButton from '../../../components/userComponents/BackButton/BackButton';
+import SpotlightDisplayButton from '../../../components/userComponents/SpotlightDisplayButton/SpotlightDisplayButton';
+import RelatedLinks from '../../../components/userComponents/RelatedLinks/RelatedLinks';
+
+/**
+ * @param params -
+ * @param params.params -
+ * @param params.params.spotlightId -
+ * @returns a spotlight page given a spotlight Id
+ */
+export default function Page({ params }: { params: { spotlightId: string } }) {
+ const [spotlight, setSpotlight] = useState();
+ const [displays, setDisplays] = useState([]);
+ const [media, setMedia] = useState([]);
+ const [tourMedia, setTourMedia] = useState([]);
+ const [allTourMedia, setAllTourMedia] = useState([]);
+ const [relatedSpotlights, setRelatedSpotlights] = useState([]);
+ const [isWide, setIsWide] = useState(false);
+
+ useEffect(() => {
+ /**
+ * @returns data from tour table and display table
+ */
+ async function fetchData() {
+ const responseDataForSpotlight: TourRow = await fetchTour(
+ params.spotlightId,
+ );
+ setSpotlight(responseDataForSpotlight);
+
+ const responseDataForDisplays: DisplayRow[] =
+ await fetchDisplayfromSpotlight(params.spotlightId);
+ setDisplays(responseDataForDisplays);
+
+ const responseDataForRelatedSpotlights: TourRow[] =
+ await fetchRelatedSpotlightsfromSpotlightId(params.spotlightId);
+ setRelatedSpotlights(responseDataForRelatedSpotlights);
+ }
+
+ // Get tour media
+ const getTourMedia = async () => {
+ const fetchedTourMedia = await fetchTourMedia(params.spotlightId);
+ setTourMedia(fetchedTourMedia);
+ };
+
+ // Get all tour media
+ const getAllTourMedia = async () => {
+ const fetchedAllTourMedia = await fetchAllTourMedia();
+ setAllTourMedia(fetchedAllTourMedia);
+ };
+
+ // Get media
+ const getMedia = async () => {
+ const fetchedMedia = await fetchMedia();
+ setMedia(fetchedMedia);
+ };
+
+ fetchData();
+ getTourMedia();
+ getMedia();
+ getAllTourMedia();
+ }, [params.spotlightId]);
+
+ useEffect(() => {
+ if (window) {
+ setIsWide(window.innerWidth >= 1024);
+ }
+ // Update isWide state on window resize
+ const handleResize = () => setIsWide(window.innerWidth >= 1024);
+ window.addEventListener('resize', handleResize);
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ };
+ }, []);
+
+ return isWide ? (
+
+
+
+
+
+
+
+
+ Home / Wildlife Spotlights
+ {' '}
+ / {spotlight?.name}
+
+
+
{spotlight?.name}
+
+
+
+
+
+
+
+ {media.length > 0 && (
+
m.id === tourMedia[0]?.media_id)?.id}
+ src={
+ media.find(m => m.id === tourMedia[0]?.media_id)?.url ??
+ ''
+ }
+ alt={
+ media.find(m => m.id === tourMedia[0]?.media_id)?.text ??
+ ''
+ }
+ className="w-full h-full object-cover"
+ />
+ )}
+
+
+
+ {spotlight?.description}
+
+
+
+
+
+
+ {relatedSpotlights.length > 0 && (
+
+
Related Spotlights
+
+
+
+ )}
+
+
+ {displays.length > 0 && (
+
+
In this spotlight...
+
+
+ {displays.map(display => (
+
+
+
+
+
+ ))}
+
+
+ )}
+
+
+
+
+ ) : (
+
+
+
+
+
+
+ {media.length > 0 && (
+
m.id === tourMedia[0]?.media_id)?.id}
+ src={media.find(m => m.id === tourMedia[0]?.media_id)?.url ?? ''}
+ alt={media.find(m => m.id === tourMedia[0]?.media_id)?.text ?? ''}
+ className="w-full h-full object-cover relative"
+ />
+ )}
+
+
+
+
+
{spotlight?.name}
+
{spotlight?.description}
+
+
+ {displays.length > 0 && (
+
+
+
In this spotlight...
+
+
+ {displays.map(display => (
+
+
+
+
+
+ ))}
+
+
+
+ )}
+
+
+
+
+
+ {relatedSpotlights.length > 0 && (
+
+
Related Spotlights
+
+
+
+ )}
+
+
+ );
+}
diff --git a/src/app/wildlife-spotlights/page.tsx b/src/app/wildlife-spotlights/page.tsx
new file mode 100644
index 00000000..9470e220
--- /dev/null
+++ b/src/app/wildlife-spotlights/page.tsx
@@ -0,0 +1,222 @@
+'use client';
+
+import Link from 'next/link';
+import React, { useEffect, useState } from 'react';
+
+import { fetchAllSpotlights } from '../../supabase/tours/queries';
+import { fetchMedia } from '../../supabase/media/queries';
+import { fetchAllTourMedia } from '../../supabase/tour_media/queries';
+import NavBar from '../../components/userComponents/NavBar/NavBar';
+import { TourRow, MediaRow, TourMediaRow } from '../../types/types';
+import { BackArrow } from '../../../public/icons';
+
+/**
+ * @returns The spotlights page.
+ */
+export default function WildlifeSpotlightsPage() {
+ const [spotlights, setSpotlights] = useState([]);
+ const [media, setMedia] = useState([]);
+ const [allTourMedia, setAllTourMedia] = useState([]);
+ const [isWide, setIsWide] = useState(false);
+
+ useEffect(() => {
+ /**
+ * @returns spotlight data
+ */
+ async function fetchData() {
+ const responseData: TourRow[] = await fetchAllSpotlights();
+ setSpotlights(responseData);
+ }
+
+ // Get all tour media
+ const getAllTourMedia = async () => {
+ const fetchedAllTourMedia = await fetchAllTourMedia();
+ setAllTourMedia(fetchedAllTourMedia);
+ };
+
+ // Get media
+ const getMedia = async () => {
+ const fetchedMedia = await fetchMedia();
+ setMedia(fetchedMedia);
+ };
+
+ fetchData();
+ getAllTourMedia();
+ getMedia();
+ }, []);
+
+ useEffect(() => {
+ if (window) {
+ setIsWide(window.innerWidth >= 1024);
+ }
+ // Update isWide state on window resize
+ const handleResize = () => setIsWide(window.innerWidth >= 1024);
+ window.addEventListener('resize', handleResize);
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ };
+ }, []);
+
+ return (
+
+
+
+ {isWide ? (
+
+
+
+ Home / Wildlife
+ Spotlights
+
+
+
Wildlife Spotlights
+
+ Wildlife Spotlights provide answers to many frequently asked
+ questions. You’ll find information on topics ranging from what
+ to do if you encounter a baby bird lost from its nest to how to
+ deal with nuisance animals in your yard.
+
+
+
+
+
+
+
+ ) : (
+
+
+
+
+
+
+
+
+
+
Wildlife Spotlights
+
+ Wildlife Spotlights provide answers to many frequently asked
+ questions. You’ll find information on topics ranging from what
+ to do if you encounter a baby bird lost from its nest to how to
+ deal with nuisance animals in your yard.
+
+
+
+
+
+
+ )}
+
+ );
+}
diff --git a/src/components/userComponents/BackButton/BackButton.tsx b/src/components/userComponents/BackButton/BackButton.tsx
index b88e1ac4..244e462f 100644
--- a/src/components/userComponents/BackButton/BackButton.tsx
+++ b/src/components/userComponents/BackButton/BackButton.tsx
@@ -1,13 +1,24 @@
-import React from 'react';
+import React, { useState } from 'react';
import { BackArrow } from '../../../../public/icons';
/**
* @returns the BackArrow button
*/
export default function BackButton() {
+ const [isClicked, setIsClicked] = useState(false);
+ const handleClick = () => {
+ setIsClicked(true);
+ };
return (
-
+
-
+
);
}
diff --git a/src/components/userComponents/ButtonWithText/ButtonWithText.tsx b/src/components/userComponents/ButtonWithText/ButtonWithText.tsx
new file mode 100644
index 00000000..06bc5a7b
--- /dev/null
+++ b/src/components/userComponents/ButtonWithText/ButtonWithText.tsx
@@ -0,0 +1,25 @@
+import React, { useState } from 'react';
+
+/**
+ * @param root0 -
+ * @param root0.text - Text to display on button
+ * @returns A button with text
+ */
+export default function ButtonWithText({ text }: { text: string }) {
+ const [isClicked, setIsClicked] = useState(false);
+ const handleClick = () => {
+ setIsClicked(true);
+ };
+ return (
+
+ {text}
+
+ );
+}
diff --git a/src/components/userComponents/ExhibitPreview/ExhibitPreview.tsx b/src/components/userComponents/ExhibitPreview/ExhibitPreview.tsx
index aeeb0315..4d7ec7d5 100644
--- a/src/components/userComponents/ExhibitPreview/ExhibitPreview.tsx
+++ b/src/components/userComponents/ExhibitPreview/ExhibitPreview.tsx
@@ -6,7 +6,6 @@ import Image from 'next/image';
import Link from 'next/link';
import styles from './ExhibitPreview.module.css';
-
/**
*
* @param props - props for the ExhibitPreview component
diff --git a/src/components/userComponents/FilterButton/FilterButton.tsx b/src/components/userComponents/FilterButton/FilterButton.tsx
index cb7eb7db..d7b6bb18 100644
--- a/src/components/userComponents/FilterButton/FilterButton.tsx
+++ b/src/components/userComponents/FilterButton/FilterButton.tsx
@@ -24,11 +24,14 @@ interface FilterButtonProps {
* @returns JSX.Element
*/
function FilterButton({ content, onClick, isSelected }: FilterButtonProps) {
- const baseStyle = 'py-2.5 px-3 whitespace-nowrap font-lato text-base font-normal rounded-lg flex-grow text-center';
+ const baseStyle =
+ 'py-2.5 px-3 whitespace-nowrap font-lato text-base font-normal rounded-lg flex-grow text-center';
const selectedStyle = 'bg-hunter-green text-white';
const unselectedStyle = 'bg-mint-cream text-scary-forest';
- const buttonClass = `${baseStyle} ${isSelected ? selectedStyle : unselectedStyle}`;
+ const buttonClass = `${baseStyle} ${
+ isSelected ? selectedStyle : unselectedStyle
+ }`;
return (
See All
diff --git a/src/components/userComponents/HomePageComponents/HomeVirtualTours/HomeVirtualTours.tsx b/src/components/userComponents/HomePageComponents/HomeVirtualTours/HomeVirtualTours.tsx
index c1c6cfba..bcb4bbde 100644
--- a/src/components/userComponents/HomePageComponents/HomeVirtualTours/HomeVirtualTours.tsx
+++ b/src/components/userComponents/HomePageComponents/HomeVirtualTours/HomeVirtualTours.tsx
@@ -48,7 +48,7 @@ function HomeVirtualTours(): React.JSX.Element {
See All
@@ -63,7 +63,7 @@ function HomeVirtualTours(): React.JSX.Element {
{tourWithMedia.map((tour: TourWithMediaRow) => (
-
+
See all virtual tours
diff --git a/src/components/userComponents/HomePageComponents/HomeWildlifeSpotlights/HomeWildlifeSpotlights.tsx b/src/components/userComponents/HomePageComponents/HomeWildlifeSpotlights/HomeWildlifeSpotlights.tsx
index 88d94e48..4f5dd282 100644
--- a/src/components/userComponents/HomePageComponents/HomeWildlifeSpotlights/HomeWildlifeSpotlights.tsx
+++ b/src/components/userComponents/HomePageComponents/HomeWildlifeSpotlights/HomeWildlifeSpotlights.tsx
@@ -48,7 +48,7 @@ function HomeWildlifeSpotlights(): React.JSX.Element {
See All
@@ -57,7 +57,10 @@ function HomeWildlifeSpotlights(): React.JSX.Element {
{spotlightsWithMedia.map((spotlight: SpotlightWithMediaRow) => (
-
+
See all wildlife spotlights
diff --git a/src/components/userComponents/HomePageComponents/VisitorResources/AdmissionButton.tsx b/src/components/userComponents/HomePageComponents/VisitorResources/AdmissionButton.tsx
index 524d5f35..21545b44 100644
--- a/src/components/userComponents/HomePageComponents/VisitorResources/AdmissionButton.tsx
+++ b/src/components/userComponents/HomePageComponents/VisitorResources/AdmissionButton.tsx
@@ -14,7 +14,7 @@ function AdmissionButton() {
bg-ivory group hover:bg-mint-cream focus:bg-mint-cream
shadow-darkest focus:shadow-vignette
px-4 py-4 web:px-8 web:py-6"
- href="/hoursAdmissionPage"
+ href="/hours-and-location"
>
+
+
{media.length > 1 && (
-
-
+
-
-
-
- )}
-
-
- {media.length > 0 && (
-
- )}
+
+
+
+
+
-
- {media.length > 1 && (
-
-
-
-
-
)}
);
diff --git a/src/components/userComponents/LastStopButton/LastStopButton.tsx b/src/components/userComponents/LastStopButton/LastStopButton.tsx
index 0eaa7253..03fc3a31 100644
--- a/src/components/userComponents/LastStopButton/LastStopButton.tsx
+++ b/src/components/userComponents/LastStopButton/LastStopButton.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState } from 'react';
import Link from 'next/link';
import { CaretLeft } from '../../../../public/icons';
@@ -14,16 +14,21 @@ interface LastStopButtonProps {
* @returns the Last Stop button
*/
export default function LastStopButton({ text, link }: LastStopButtonProps) {
+ const [isClicked, setIsClicked] = useState(false);
+ const handleClick = () => {
+ setIsClicked(true);
+ };
return (
);
diff --git a/src/components/userComponents/NextStopButton/NextStopButton.tsx b/src/components/userComponents/NextStopButton/NextStopButton.tsx
index 53f404a7..5059154e 100644
--- a/src/components/userComponents/NextStopButton/NextStopButton.tsx
+++ b/src/components/userComponents/NextStopButton/NextStopButton.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState } from 'react';
import Link from 'next/link';
import { CaretRight } from '../../../../public/icons';
@@ -14,13 +14,20 @@ interface NextStopButtonProps {
* @returns the Next Stop button
*/
export default function NextStopButton({ text, link }: NextStopButtonProps) {
+ const [isClicked, setIsClicked] = useState(false);
+ const handleClick = () => {
+ setIsClicked(true);
+ };
return (
diff --git a/src/components/userComponents/ProgressBar/ProgressBar.tsx b/src/components/userComponents/ProgressBar/ProgressBar.tsx
index 79127d38..4016cc4d 100644
--- a/src/components/userComponents/ProgressBar/ProgressBar.tsx
+++ b/src/components/userComponents/ProgressBar/ProgressBar.tsx
@@ -18,9 +18,9 @@ function ProgressBar({ tourName, currentStop, totalStops }: ProgressBarProps) {
return (
-
-
-
{tourName} Tour
+
+
+
{tourName} Tour
-
+
{currentStop}/{totalStops}
-
+
diff --git a/src/components/userComponents/RelatedLinks/RelatedLinks.tsx b/src/components/userComponents/RelatedLinks/RelatedLinks.tsx
new file mode 100644
index 00000000..84139e19
--- /dev/null
+++ b/src/components/userComponents/RelatedLinks/RelatedLinks.tsx
@@ -0,0 +1,61 @@
+import React, { useEffect, useState } from 'react';
+
+import { LinksRow } from '../../../types/types';
+
+import fetchAllLinks from '../../../supabase/links/queries';
+import { ExternalLinkIcon } from '../../../../public/icons';
+
+/**
+ * @returns the Related Links component
+ */
+export default function RelatedLinks() {
+ const [links, setLinks] = useState
([]);
+
+ useEffect(() => {
+ const fetchData = async () => {
+ const fetchedLinks = await fetchAllLinks();
+ setLinks(fetchedLinks);
+ };
+ fetchData();
+ }, []);
+
+ if (links.length === 0) {
+ return null;
+ }
+
+ return (
+
+ );
+}
diff --git a/src/components/userComponents/SiteMap/ExhibitPreviewCard.tsx b/src/components/userComponents/SiteMap/ExhibitPreviewCard.tsx
index 4260aa3b..6c80c793 100644
--- a/src/components/userComponents/SiteMap/ExhibitPreviewCard.tsx
+++ b/src/components/userComponents/SiteMap/ExhibitPreviewCard.tsx
@@ -51,7 +51,6 @@ function ExhibitPreviewCard({
}
}, [isWebDevice]);
-
useEffect(() => {
handleResize();
window.addEventListener('resize', handleResize);
@@ -72,18 +71,18 @@ function ExhibitPreviewCard({
useEffect(() => {
const fetchDetails = async () => {
if (!tour.image) {
- setLoading(true);
-
- let imageUrl = '';
- let displayName = '';
-
- imageUrl = tour.image;
- displayName = tour.category;
+ setLoading(true);
+
+ let imageUrl = '';
+ let displayName = '';
- // Set state variables
- setPreviewImage(imageUrl);
- setname1(displayName);
- setLoading(false);
+ imageUrl = tour.image;
+ displayName = tour.category;
+
+ // Set state variables
+ setPreviewImage(imageUrl);
+ setname1(displayName);
+ setLoading(false);
}
};
@@ -93,48 +92,78 @@ function ExhibitPreviewCard({
/** route this to spotlights */
return (
-
-
- {!loading && (
-
-
-
- )}
-
{
- if (handleClick && e.key === 'Enter') {
- handleClick();
- }
- }} role="button" tabIndex={0}>
-
-
{
- e.stopPropagation();
- handleClose();
- }}>
-
-
-
-
+
+
+ {!loading && (
+
+
-
-
- {name1}
+ )}
+
{
+ if (handleClick && e.key === 'Enter') {
+ handleClick();
+ }
+ }}
+ role="button"
+ tabIndex={0}
+ >
+
+
{
+ e.stopPropagation();
+ handleClose();
+ }}
+ >
+
+
+
+
+
+
+
+ {name1}
+
-
- {description}
-
-
- Go to exhibit >
-
-
+
+
+ {description}{' '}
+
+
+
+ Go to exhibit >
+
+
+
-
);
}
diff --git a/src/components/userComponents/SiteMap/MapInteractionHandler.tsx b/src/components/userComponents/SiteMap/MapInteractionHandler.tsx
index 289afc93..a99f9746 100644
--- a/src/components/userComponents/SiteMap/MapInteractionHandler.tsx
+++ b/src/components/userComponents/SiteMap/MapInteractionHandler.tsx
@@ -7,7 +7,7 @@ import { LatLngExpression } from 'leaflet';
* @param {L.LatLng} props.center - The center to which the map should fly. Must include 'lat' and 'lng' properties.
* @returns {null} Nothing is rendered by this component.
*/
-function RecenterMap({ center } : { center: LatLngExpression }) {
+function RecenterMap({ center }: { center: LatLngExpression }) {
const map = useMap();
useEffect(() => {
diff --git a/src/components/userComponents/SiteMap/SiteMap.tsx b/src/components/userComponents/SiteMap/SiteMap.tsx
index 5605d6d6..50c22a5e 100644
--- a/src/components/userComponents/SiteMap/SiteMap.tsx
+++ b/src/components/userComponents/SiteMap/SiteMap.tsx
@@ -62,15 +62,16 @@ function SiteMap({ mode }: SiteMapProps) {
const [selectedMarker, setSelectedMarker] = useState
(null);
const [loading, setLoading] = useState(true);
const isWebDevice = useWebDeviceDetection();
- const cacheRef = useRef<{ tours?: TourRow[], exhibits?: ExhibitWithCategoryRow[] }>({});
+ const cacheRef = useRef<{
+ tours?: TourRow[];
+ exhibits?: ExhibitWithCategoryRow[];
+ }>({});
-
-
useEffect(() => {
/**
* This useEffect will manage fetching Data depending on if the chosen map is tours or exhibits.
* It will also manage the initial state of the map when no marker is chosen
- *
+ *
* It will fetch tours when spotlights == True
*/
async function fetchData() {
@@ -125,7 +126,6 @@ function SiteMap({ mode }: SiteMapProps) {
setSelectedTour(null);
}, [mode]);
-
useEffect(() => {
if (!selectedTour) {
setSelectedMarker(null);
@@ -184,17 +184,17 @@ function SiteMap({ mode }: SiteMapProps) {
);
})
)}
- {selectedTour && (
- isWebDevice ? (
+ {selectedTour &&
+ (isWebDevice ? (
{mode === 'tours' ? (
) : (
)}
@@ -203,22 +203,21 @@ function SiteMap({ mode }: SiteMapProps) {
{mode === 'tours' ? (
) : (
)}
- )
- )}
-
+ ))}
+
{selectedTour == null && }
);
}
-export default SiteMap;
\ No newline at end of file
+export default SiteMap;
diff --git a/src/components/userComponents/SiteMap/TourPreviewCard.tsx b/src/components/userComponents/SiteMap/TourPreviewCard.tsx
index 94bac316..50d16791 100644
--- a/src/components/userComponents/SiteMap/TourPreviewCard.tsx
+++ b/src/components/userComponents/SiteMap/TourPreviewCard.tsx
@@ -13,13 +13,17 @@ interface TourCardProps {
/**
* Represents a preview card for a tour.
- *
+ *
* @param {TourRow} tour - The tour data.
* @param {Function} handleClick - The function to call when the card is clicked.
* @param {Function} handleClose - The function to call to close the card.
* @returns {JSX.Element} The component UI.
*/
-function TourPreviewCard({ tour, handleClick, handleClose }: TourCardProps): JSX.Element {
+function TourPreviewCard({
+ tour,
+ handleClick,
+ handleClose,
+}: TourCardProps): JSX.Element {
const [loading, setLoading] = useState(false);
const [previewImage, setPreviewImage] = useState('');
const [name1, setname1] = useState('');
@@ -62,44 +66,76 @@ function TourPreviewCard({ tour, handleClick, handleClose }: TourCardProps): JSX
}, [tour]);
return (
-
-
+
+
{!loading && (
+ />
)}
-
{
- if (e.key === 'Enter' && handleClick) {
- handleClick();
- }
- }} role="button" tabIndex={0}>
+
{
+ if (e.key === 'Enter' && handleClick) {
+ handleClick();
+ }
+ }}
+ role="button"
+ tabIndex={0}
+ >
-
{
e.stopPropagation();
- handleClose();
- }}>
-
-
{category}
+ handleClose();
+ }}
+ >
+
+
+ {category}
+
-
-
+
+
-
+
- {name1}
+
+ {name1}
+
- {description}
+
+ {description}
+
-
+
Go to virtual tour >
diff --git a/src/components/userComponents/SpotlightDisplayButton/SpotlightDisplayButton.tsx b/src/components/userComponents/SpotlightDisplayButton/SpotlightDisplayButton.tsx
new file mode 100644
index 00000000..193f857c
--- /dev/null
+++ b/src/components/userComponents/SpotlightDisplayButton/SpotlightDisplayButton.tsx
@@ -0,0 +1,25 @@
+import React, { useState } from 'react';
+
+/**
+ * @param root0 -
+ * @param root0.text - Text to display on button
+ * @returns A spotlight display button
+ */
+export default function SpotlightDisplayButton({ text }: { text: string }) {
+ const [isClicked, setIsClicked] = useState(false);
+ const handleClick = () => {
+ setIsClicked(true);
+ };
+ return (
+
+ {text}
+
+ );
+}
diff --git a/src/components/userComponents/TextButton/TextButton.tsx b/src/components/userComponents/TextButton/TextButton.tsx
new file mode 100644
index 00000000..a47e59f4
--- /dev/null
+++ b/src/components/userComponents/TextButton/TextButton.tsx
@@ -0,0 +1,23 @@
+import React, { useState } from 'react';
+
+/**
+ * @param root0 -
+ * @param root0.text - Text to display
+ * @returns A text that acts like a button
+ */
+export default function TextButton({ text }: { text: string }) {
+ const [isClicked, setIsClicked] = useState(false);
+ const handleClick = () => {
+ setIsClicked(true);
+ };
+ return (
+
+ {text}
+
+ );
+}
diff --git a/src/components/userComponents/emailPopup/page.tsx b/src/components/userComponents/emailPopup/page.tsx
index b1e40683..af4b9353 100644
--- a/src/components/userComponents/emailPopup/page.tsx
+++ b/src/components/userComponents/emailPopup/page.tsx
@@ -148,20 +148,20 @@ export default function EmailPopup({ backLink }: { backLink: string }) {
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- const handleChange = (e : any) => {
+ const handleChange = (e: any) => {
setInputValue(e.target.value);
setShowError(false);
};
// const { error } = await supabase.from('emails').insert({ id: 1, name: 'Denmark' })
- const isValidEmail = (email : string) => {
+ const isValidEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.(com|ca)$/;
return emailRegex.test(email);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any, consistent-return
- const handleSubmit = async (e : any) => {
+ const handleSubmit = async (e: any) => {
e.preventDefault();
if (!inputValue.trim()) {
diff --git a/src/components/userComponents/navBar/navBar.tsx b/src/components/userComponents/navBar/navBar.tsx
index c524076f..d9864e07 100644
--- a/src/components/userComponents/navBar/navBar.tsx
+++ b/src/components/userComponents/navBar/navBar.tsx
@@ -1,5 +1,6 @@
-import React, { useState, useEffect } from 'react';
import Link from 'next/link';
+import React, { useState, useEffect } from 'react';
+
import { HamburgerMenu, CloseMenu } from '../../../../public/icons';
/**
@@ -7,6 +8,7 @@ import { HamburgerMenu, CloseMenu } from '../../../../public/icons';
*/
export default function NavBar() {
const [showMenu, setShowMenu] = useState(false);
+ const [isWide, setIsWide] = useState(false);
useEffect(() => {
if (showMenu) {
@@ -16,6 +18,18 @@ export default function NavBar() {
}
}, [showMenu]);
+ useEffect(() => {
+ if (window) {
+ setIsWide(window.innerWidth >= 1024);
+ }
+ // Update isWide state on window resize
+ const handleResize = () => setIsWide(window.innerWidth >= 1024);
+ window.addEventListener('resize', handleResize);
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ };
+ }, []);
+
/**
* Toggles the side menu
*/
@@ -23,85 +37,87 @@ export default function NavBar() {
setShowMenu(!showMenu);
}
- return (
-
-
+ return isWide ? (
+
+
-
-
- {showMenu ? : }
-
-
+
+ Hours & Location
+ Exhibits
+ Site Maps
+ Virtual Tours
+ Wildlife Spotlights
+ News
+
+
+
+
+ ) : (
+
+
+
+
+
+
+
+
+ {showMenu ? : }
+
+
+
+
-
{showMenu && (
-
-
-
- WELCOME
-
-
- Home
-
-
-
- VISIT
-
-
- Hours & Location
-
-
- Site Maps
-
-
- Exhibits
-
-
-
- LEARN & EXPLORE
-
-
- Virtual Tours
-
-
- Wildlife Spotlights
-
-
- News
-
+
+
+
+
+
+
VISIT
+
+ Hours & Location
+ Site Maps
+ Exhibits
+
+
+
+
+
+ LEARN & EXPLORE
+
+
+ Virtual Tours
+ Wildlife Spotlights
+ News
+
+
+
)}
diff --git a/src/supabase/category/queries.ts b/src/supabase/category/queries.ts
index 7dc61968..5dd7978f 100644
--- a/src/supabase/category/queries.ts
+++ b/src/supabase/category/queries.ts
@@ -8,30 +8,29 @@ import { CategoryRow } from '../../types/types';
* @returns color for category, else null
*/
// eslint-disable-next-line import/prefer-default-export
-export async function getCategoryColor1(id: string|number) {
- try {
- const { data, error } = await supabase
- .from('categories')
- .select('color_hex')
- .eq('id', id);
+export async function getCategoryColor1(id: string | number) {
+ try {
+ const { data, error } = await supabase
+ .from('categories')
+ .select('color_hex')
+ .eq('id', id);
if (error) {
console.error('Error fetching from Supabase:', error.message);
return null; // Return null on query error
}
- // Check if data array is not empty
- if (data && data.length > 0 && data[0].color_hex) {
- // console.log(`Color for ${category}:`, data[0].color_hex);
- return data[0].color_hex;
- }
- console.log("No matching category found or color_hex is undefined");
- return null; // Return null if no matching data found
-
- } catch (error) {
- console.error(`An unexpected error occurred:`, error);
- return null; // Return null on unexpected error
+ // Check if data array is not empty
+ if (data && data.length > 0 && data[0].color_hex) {
+ // console.log(`Color for ${category}:`, data[0].color_hex);
+ return data[0].color_hex;
}
+ console.log('No matching category found or color_hex is undefined');
+ return null; // Return null if no matching data found
+ } catch (error) {
+ console.error(`An unexpected error occurred:`, error);
+ return null; // Return null on unexpected error
+ }
}
/**
@@ -39,9 +38,9 @@ export async function getCategoryColor1(id: string|number) {
* @returns A promise that resolves to an array of ExhibitRow objects.
*/
export async function fetchAllCategories(): Promise
{
- const { data, error } = await supabase.from('categories').select('*');
- if (error) {
- throw new Error(error.message);
- }
- return data;
- }
\ No newline at end of file
+ const { data, error } = await supabase.from('categories').select('*');
+ if (error) {
+ throw new Error(error.message);
+ }
+ return data;
+}
diff --git a/src/supabase/displays/queries.tsx b/src/supabase/displays/queries.tsx
index ce7e37db..f2e1d925 100644
--- a/src/supabase/displays/queries.tsx
+++ b/src/supabase/displays/queries.tsx
@@ -41,7 +41,7 @@ export async function deleteDisplay(id: string) {
if (error) {
throw new Error(`An error occurred trying to delete displays: ${error}`);
} else {
- fetchDisplays();
+ fetchDisplay(id);
}
}
diff --git a/src/supabase/links/queries.tsx b/src/supabase/links/queries.tsx
new file mode 100644
index 00000000..d77fd9c6
--- /dev/null
+++ b/src/supabase/links/queries.tsx
@@ -0,0 +1,16 @@
+'use client';
+
+import supabase from '../client';
+import { LinksRow } from '../../types/types';
+
+/**
+ * Fetches all links from the database.
+ * @returns A promise that resolves to an array of LinksRow objects.
+ */
+export default async function fetchAllLinks(): Promise {
+ const { data, error } = await supabase.rpc('get_links');
+ if (error) {
+ throw new Error(error.message);
+ }
+ return data;
+}
diff --git a/src/supabase/media/queries.ts b/src/supabase/media/queries.ts
index 891ba21e..e0505e0a 100644
--- a/src/supabase/media/queries.ts
+++ b/src/supabase/media/queries.ts
@@ -36,7 +36,7 @@ export async function fetchImagesForDisplay(displayId: string | undefined) {
/**
*
- * @param tourId id of the tour to fetch images for
+ * @param tourId id of the tour to fetch images for
* @returns an array of image objects corresponding to the display
*/
export async function fetchImagesForTour(
@@ -53,7 +53,7 @@ export async function fetchImagesForTour(
throw new Error(error.message);
}
- return data;
+ return data;
}
/**
*
diff --git a/src/supabase/tour_displays/queries.tsx b/src/supabase/tour_displays/queries.tsx
index 2dd16c73..66f5522f 100644
--- a/src/supabase/tour_displays/queries.tsx
+++ b/src/supabase/tour_displays/queries.tsx
@@ -41,8 +41,9 @@ export async function fetchMatchingTourDisplayIdsfromSpotlight(tourId: string) {
* @returns given a spotlight ID, get all the displays
*/
export async function fetchDisplayfromSpotlight(spotlightId: string) {
- const displayIds: string[] =
- await fetchMatchingTourDisplayIdsfromSpotlight(spotlightId);
+ const displayIds: string[] = await fetchMatchingTourDisplayIdsfromSpotlight(
+ spotlightId,
+ );
const displays: DisplayRow[] = await fetchDisplaysfromIds(displayIds);
return displays;
}
diff --git a/src/types/supabase.ts b/src/types/supabase.ts
index 568c97e6..15874327 100644
--- a/src/types/supabase.ts
+++ b/src/types/supabase.ts
@@ -4,548 +4,558 @@ export type Json =
| boolean
| null
| { [key: string]: Json | undefined }
- | Json[]
+ | Json[];
export type Database = {
public: {
Tables: {
categories: {
Row: {
- category: string | null
- color_hex: string
- created_at: string
- description: string
- id: number
- image: string
- }
+ category: string | null;
+ color_hex: string;
+ created_at: string;
+ description: string | null;
+ id: number;
+ image: string | null;
+ };
Insert: {
- category?: string | null
- color_hex: string
- created_at?: string
- description: string
- id?: number
- image: string
- }
+ category?: string | null;
+ color_hex: string;
+ created_at?: string;
+ description?: string | null;
+ id?: number;
+ image?: string | null;
+ };
Update: {
- category?: string | null
- color_hex?: string
- created_at?: string
- description?: string
- id?: number
- image?: string
- }
- Relationships: []
- }
+ category?: string | null;
+ color_hex?: string;
+ created_at?: string;
+ description?: string | null;
+ id?: number;
+ image?: string | null;
+ };
+ Relationships: [];
+ };
display_media: {
Row: {
- display_id: string
- media_id: string
- media_placement: string | null
- }
+ display_id: string;
+ media_id: string;
+ media_placement: string | null;
+ };
Insert: {
- display_id: string
- media_id: string
- media_placement?: string | null
- }
+ display_id: string;
+ media_id: string;
+ media_placement?: string | null;
+ };
Update: {
- display_id?: string
- media_id?: string
- media_placement?: string | null
- }
+ display_id?: string;
+ media_id?: string;
+ media_placement?: string | null;
+ };
Relationships: [
{
- foreignKeyName: "display_media_display_id_fkey"
- columns: ["display_id"]
- isOneToOne: false
- referencedRelation: "displays"
- referencedColumns: ["id"]
+ foreignKeyName: 'display_media_display_id_fkey';
+ columns: ['display_id'];
+ isOneToOne: false;
+ referencedRelation: 'displays';
+ referencedColumns: ['id'];
},
{
- foreignKeyName: "display_media_media_id_fkey"
- columns: ["media_id"]
- isOneToOne: false
- referencedRelation: "media"
- referencedColumns: ["id"]
+ foreignKeyName: 'display_media_media_id_fkey';
+ columns: ['media_id'];
+ isOneToOne: false;
+ referencedRelation: 'media';
+ referencedColumns: ['id'];
},
- ]
- }
+ ];
+ };
displays: {
Row: {
- coordinates: Json | null
- created_at: string
- description: string
- id: string
- title: string
- updated_at: string | null
- }
+ coordinates: Json | null;
+ created_at: string;
+ description: string;
+ id: string;
+ title: string;
+ updated_at: string | null;
+ };
Insert: {
- coordinates?: Json | null
- created_at?: string
- description?: string
- id?: string
- title?: string
- updated_at?: string | null
- }
+ coordinates?: Json | null;
+ created_at?: string;
+ description?: string;
+ id?: string;
+ title?: string;
+ updated_at?: string | null;
+ };
Update: {
- coordinates?: Json | null
- created_at?: string
- description?: string
- id?: string
- title?: string
- updated_at?: string | null
- }
- Relationships: []
- }
+ coordinates?: Json | null;
+ created_at?: string;
+ description?: string;
+ id?: string;
+ title?: string;
+ updated_at?: string | null;
+ };
+ Relationships: [];
+ };
emails: {
Row: {
- emails: string | null
- id: number
- }
+ emails: string | null;
+ first_name: string | null;
+ id: number;
+ };
Insert: {
- emails?: string | null
- id?: number
- }
+ emails?: string | null;
+ first_name?: string | null;
+ id?: number;
+ };
Update: {
- emails?: string | null
- id?: number
- }
- Relationships: []
- }
+ emails?: string | null;
+ first_name?: string | null;
+ id?: number;
+ };
+ Relationships: [];
+ };
exhibits: {
Row: {
- category_id: number
- coordinates: Json | null
- id: string
- title: string
- }
+ category_id: number;
+ coordinates: Json | null;
+ id: string;
+ title: string;
+ };
Insert: {
- category_id: number
- coordinates?: Json | null
- id?: string
- title: string
- }
+ category_id: number;
+ coordinates?: Json | null;
+ id?: string;
+ title: string;
+ };
Update: {
- category_id?: number
- coordinates?: Json | null
- id?: string
- title?: string
- }
+ category_id?: number;
+ coordinates?: Json | null;
+ id?: string;
+ title?: string;
+ };
Relationships: [
{
- foreignKeyName: "public_exhibits_category_id_fkey"
- columns: ["category_id"]
- isOneToOne: false
- referencedRelation: "categories"
- referencedColumns: ["id"]
+ foreignKeyName: 'public_exhibits_category_id_fkey';
+ columns: ['category_id'];
+ isOneToOne: false;
+ referencedRelation: 'categories';
+ referencedColumns: ['id'];
},
- ]
- }
+ ];
+ };
+ links: {
+ Row: {
+ created_at: string;
+ id: string;
+ title: string | null;
+ type: string | null;
+ url: string | null;
+ };
+ Insert: {
+ created_at?: string;
+ id?: string;
+ title?: string | null;
+ type?: string | null;
+ url?: string | null;
+ };
+ Update: {
+ created_at?: string;
+ id?: string;
+ title?: string | null;
+ type?: string | null;
+ url?: string | null;
+ };
+ Relationships: [];
+ };
media: {
Row: {
- created_at: string
- id: string
- text: string | null
- title: string | null
- type: string | null
- url: string
- }
+ created_at: string;
+ id: string;
+ text: string | null;
+ title: string | null;
+ type: string | null;
+ url: string;
+ };
Insert: {
- created_at?: string
- id?: string
- text?: string | null
- title?: string | null
- type?: string | null
- url?: string
- }
+ created_at?: string;
+ id?: string;
+ text?: string | null;
+ title?: string | null;
+ type?: string | null;
+ url?: string;
+ };
Update: {
- created_at?: string
- id?: string
- text?: string | null
- title?: string | null
- type?: string | null
- url?: string
- }
- Relationships: []
- }
+ created_at?: string;
+ id?: string;
+ text?: string | null;
+ title?: string | null;
+ type?: string | null;
+ url?: string;
+ };
+ Relationships: [];
+ };
news: {
Row: {
- content_link: string
- created_at: string
- id: string
- title: string
- updated_at: string | null
- }
+ content_link: string;
+ created_at: string;
+ id: string;
+ title: string;
+ updated_at: string | null;
+ };
Insert: {
- content_link: string
- created_at?: string
- id?: string
- title: string
- updated_at?: string | null
- }
+ content_link: string;
+ created_at?: string;
+ id?: string;
+ title: string;
+ updated_at?: string | null;
+ };
Update: {
- content_link?: string
- created_at?: string
- id?: string
- title?: string
- updated_at?: string | null
- }
- Relationships: []
- }
+ content_link?: string;
+ created_at?: string;
+ id?: string;
+ title?: string;
+ updated_at?: string | null;
+ };
+ Relationships: [];
+ };
spotlight_recommendations: {
Row: {
- source_display_id: string
- target_display_id: string
- }
+ source_display_id: string;
+ target_display_id: string;
+ };
Insert: {
- source_display_id: string
- target_display_id: string
- }
+ source_display_id: string;
+ target_display_id: string;
+ };
Update: {
- source_display_id?: string
- target_display_id?: string
- }
+ source_display_id?: string;
+ target_display_id?: string;
+ };
Relationships: [
{
- foreignKeyName: "spotlight_recommendations_source_display_id_fkey"
- columns: ["source_display_id"]
- isOneToOne: false
- referencedRelation: "tours"
- referencedColumns: ["id"]
+ foreignKeyName: 'spotlight_recommendations_source_display_id_fkey';
+ columns: ['source_display_id'];
+ isOneToOne: false;
+ referencedRelation: 'tours';
+ referencedColumns: ['id'];
},
{
- foreignKeyName: "spotlight_recommendations_target_display_id_fkey"
- columns: ["target_display_id"]
- isOneToOne: false
- referencedRelation: "tours"
- referencedColumns: ["id"]
+ foreignKeyName: 'spotlight_recommendations_target_display_id_fkey';
+ columns: ['target_display_id'];
+ isOneToOne: false;
+ referencedRelation: 'tours';
+ referencedColumns: ['id'];
},
- ]
- }
+ ];
+ };
tour_displays: {
Row: {
- display_id: string
- display_order: number | null
- tour_id: string
- }
+ display_id: string;
+ display_order: number | null;
+ tour_id: string;
+ };
Insert: {
- display_id: string
- display_order?: number | null
- tour_id: string
- }
+ display_id: string;
+ display_order?: number | null;
+ tour_id: string;
+ };
Update: {
- display_id?: string
- display_order?: number | null
- tour_id?: string
- }
+ display_id?: string;
+ display_order?: number | null;
+ tour_id?: string;
+ };
Relationships: [
{
- foreignKeyName: "tour_displays_display_id_fkey"
- columns: ["display_id"]
- isOneToOne: false
- referencedRelation: "displays"
- referencedColumns: ["id"]
+ foreignKeyName: 'tour_displays_display_id_fkey';
+ columns: ['display_id'];
+ isOneToOne: false;
+ referencedRelation: 'displays';
+ referencedColumns: ['id'];
},
{
- foreignKeyName: "tour_displays_tour_id_fkey"
- columns: ["tour_id"]
- isOneToOne: false
- referencedRelation: "tours"
- referencedColumns: ["id"]
+ foreignKeyName: 'tour_displays_tour_id_fkey';
+ columns: ['tour_id'];
+ isOneToOne: false;
+ referencedRelation: 'tours';
+ referencedColumns: ['id'];
},
- ]
- }
+ ];
+ };
tour_media: {
Row: {
- media_id: string
- tour_id: string
- }
+ media_id: string;
+ tour_id: string;
+ };
Insert: {
- media_id: string
- tour_id: string
- }
+ media_id: string;
+ tour_id: string;
+ };
Update: {
- media_id?: string
- tour_id?: string
- }
+ media_id?: string;
+ tour_id?: string;
+ };
Relationships: [
{
- foreignKeyName: "tour_media_media_id_fkey"
- columns: ["media_id"]
- isOneToOne: false
- referencedRelation: "media"
- referencedColumns: ["id"]
+ foreignKeyName: 'tour_media_media_id_fkey';
+ columns: ['media_id'];
+ isOneToOne: false;
+ referencedRelation: 'media';
+ referencedColumns: ['id'];
},
{
- foreignKeyName: "tour_media_tour_id_fkey"
- columns: ["tour_id"]
- isOneToOne: false
- referencedRelation: "tours"
- referencedColumns: ["id"]
+ foreignKeyName: 'tour_media_tour_id_fkey';
+ columns: ['tour_id'];
+ isOneToOne: false;
+ referencedRelation: 'tours';
+ referencedColumns: ['id'];
},
- ]
- }
+ ];
+ };
tours: {
Row: {
- category: Database["public"]["Enums"]["tour_category"]
- coordinates: Json | null
- created_at: string
- description: string | null
- id: string
- name: string
- preview_text: string | null
- spotlight: boolean
- stop_count: number | null
- }
+ category: Database['public']['Enums']['tour_category'];
+ coordinates: Json | null;
+ created_at: string;
+ description: string | null;
+ id: string;
+ name: string;
+ preview_text: string | null;
+ spotlight: boolean;
+ stop_count: number | null;
+ };
Insert: {
- category?: Database["public"]["Enums"]["tour_category"]
- coordinates?: Json | null
- created_at?: string
- description?: string | null
- id?: string
- name: string
- preview_text?: string | null
- spotlight?: boolean
- stop_count?: number | null
- }
+ category?: Database['public']['Enums']['tour_category'];
+ coordinates?: Json | null;
+ created_at?: string;
+ description?: string | null;
+ id?: string;
+ name: string;
+ preview_text?: string | null;
+ spotlight?: boolean;
+ stop_count?: number | null;
+ };
Update: {
- category?: Database["public"]["Enums"]["tour_category"]
- coordinates?: Json | null
- created_at?: string
- description?: string | null
- id?: string
- name?: string
- preview_text?: string | null
- spotlight?: boolean
- stop_count?: number | null
- }
- Relationships: []
- }
- }
+ category?: Database['public']['Enums']['tour_category'];
+ coordinates?: Json | null;
+ created_at?: string;
+ description?: string | null;
+ id?: string;
+ name?: string;
+ preview_text?: string | null;
+ spotlight?: boolean;
+ stop_count?: number | null;
+ };
+ Relationships: [];
+ };
+ };
Views: {
- [_ in never]: never
- }
+ [_ in never]: never;
+ };
Functions: {
fetch_recommended_spotlights: {
Args: {
- source_spotlight_id: string
- }
+ source_spotlight_id: string;
+ };
Returns: {
- id: string
- name: string
- description: string
- created_at: string
- stop_count: number
- spotlight: boolean
- preview_text: string
- coordinates: Json
- category: Database["public"]["Enums"]["tour_category"]
- }[]
- }
+ id: string;
+ name: string;
+ description: string;
+ created_at: string;
+ stop_count: number;
+ spotlight: boolean;
+ preview_text: string;
+ coordinates: Json;
+ category: Database['public']['Enums']['tour_category'];
+ }[];
+ };
fetchimagesfordisplay: {
Args: {
- displayid: string
- }
+ displayid: string;
+ };
Returns: {
- id: string
- url: string
- type: string
- title: string
- text: string
- created_at: string
- }[]
- }
+ id: string;
+ url: string;
+ type: string;
+ title: string;
+ text: string;
+ created_at: string;
+ }[];
+ };
fetchimagesfortour: {
Args: {
- tourid: string
- }
+ tourid: string;
+ };
Returns: {
- id: string
- url: string
- type: string
- title: string
- text: string
- created_at: string
- }[]
- }
+ id: string;
+ url: string;
+ type: string;
+ title: string;
+ text: string;
+ created_at: string;
+ }[];
+ };
get_category_color: {
Args: {
- category_in: string
- }
- Returns: string
- }
+ category_in: string;
+ };
+ Returns: string;
+ };
get_exhibit_details: {
- Args: Record
+ Args: Record;
Returns: {
- coordinates: Json
- id: number
- category: string
- description: string
- image: string
- }[]
- }
+ coordinates: Json;
+ id: number;
+ category: string;
+ description: string;
+ image: string;
+ }[];
+ };
+ get_links: {
+ Args: Record;
+ Returns: {
+ id: string;
+ created_at: string;
+ type: string;
+ title: string;
+ url: string;
+ }[];
+ };
get_non_spotlight_tours: {
- Args: Record
+ Args: Record;
Returns: {
- id: string
- name: string
- description: string
- created_at: string
- stop_count: number
- spotlight: boolean
- preview_text: string
- coordinates: Json
- category: Database["public"]["Enums"]["tour_category"]
- }[]
- }
+ id: string;
+ name: string;
+ description: string;
+ created_at: string;
+ stop_count: number;
+ spotlight: boolean;
+ preview_text: string;
+ coordinates: Json;
+ category: Database['public']['Enums']['tour_category'];
+ }[];
+ };
join_all_spotlights_with_media: {
- Args: Record
+ Args: Record;
Returns: {
- id: string
- name: string
- description: string
- created_at: string
- stop_count: number
- spotlight: boolean
- preview_text: string
- coordinates: Json
- category: Database["public"]["Enums"]["tour_category"]
- media_url: string
- }[]
- }
- join_all_tours_with_media: {
- Args: Record
- id: string
- name: string
- description: string
- created_at: string
- stop_count: number
- spotlight: boolean
- preview_text: string
- coordinates: Json
- category: Database["public"]["Enums"]["tour_category"]
- media_url: string
- }[]
- }
+ id: string;
+ name: string;
+ description: string;
+ created_at: string;
+ stop_count: number;
+ spotlight: boolean;
+ preview_text: string;
+ coordinates: Json;
+ category: Database['public']['Enums']['tour_category'];
+ media_url: string;
+ }[];
+ };
join_all_tours_with_media: {
- Args: Record
+ Args: Record;
Returns: {
- id: string
- name: string
- description: string
- created_at: string
- stop_count: number
- spotlight: boolean
- preview_text: string
- coordinates: Json
- category: Database["public"]["Enums"]["tour_category"]
- media_url: string
- }[]
- }
- }
- id: string
- name: string
- description: string
- created_at: string
- stop_count: number
- spotlight: boolean
- preview_text: string
- coordinates: Json
- category: Database["public"]["Enums"]["tour_category"]
- media_url: string
- }[]
- }
- }
+ id: string;
+ name: string;
+ description: string;
+ created_at: string;
+ stop_count: number;
+ spotlight: boolean;
+ preview_text: string;
+ coordinates: Json;
+ category: Database['public']['Enums']['tour_category'];
+ media_url: string;
+ }[];
+ };
+ };
Enums: {
- media_type: "image" | "video" | "link"
+ media_type: 'image' | 'video' | 'link';
tour_category:
- | "BuildingsAndServices"
- | "ParksAviariesEnclosures"
- | "SiteFeatures"
- }
+ | 'BuildingsAndServices'
+ | 'ParksAviariesEnclosures'
+ | 'SiteFeatures';
+ };
CompositeTypes: {
- [_ in never]: never
- }
- }
-}
+ [_ in never]: never;
+ };
+ };
+};
-type PublicSchema = Database[Extract]
+type PublicSchema = Database[Extract];
export type Tables<
PublicTableNameOrOptions extends
- | keyof (PublicSchema["Tables"] & PublicSchema["Views"])
+ | keyof (PublicSchema['Tables'] & PublicSchema['Views'])
| { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
- ? keyof (Database[PublicTableNameOrOptions["schema"]]["Tables"] &
- Database[PublicTableNameOrOptions["schema"]]["Views"])
+ ? keyof (Database[PublicTableNameOrOptions['schema']]['Tables'] &
+ Database[PublicTableNameOrOptions['schema']]['Views'])
: never = never,
> = PublicTableNameOrOptions extends { schema: keyof Database }
- ? (Database[PublicTableNameOrOptions["schema"]]["Tables"] &
- Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends {
- Row: infer R
+ ? (Database[PublicTableNameOrOptions['schema']]['Tables'] &
+ Database[PublicTableNameOrOptions['schema']]['Views'])[TableName] extends {
+ Row: infer R;
}
? R
: never
- : PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] &
- PublicSchema["Views"])
- ? (PublicSchema["Tables"] &
- PublicSchema["Views"])[PublicTableNameOrOptions] extends {
- Row: infer R
- }
- ? R
- : never
+ : PublicTableNameOrOptions extends keyof (PublicSchema['Tables'] &
+ PublicSchema['Views'])
+ ? (PublicSchema['Tables'] &
+ PublicSchema['Views'])[PublicTableNameOrOptions] extends {
+ Row: infer R;
+ }
+ ? R
: never
+ : never;
export type TablesInsert<
PublicTableNameOrOptions extends
- | keyof PublicSchema["Tables"]
+ | keyof PublicSchema['Tables']
| { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
- ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"]
+ ? keyof Database[PublicTableNameOrOptions['schema']]['Tables']
: never = never,
> = PublicTableNameOrOptions extends { schema: keyof Database }
- ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends {
- Insert: infer I
+ ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends {
+ Insert: infer I;
}
? I
: never
- : PublicTableNameOrOptions extends keyof PublicSchema["Tables"]
- ? PublicSchema["Tables"][PublicTableNameOrOptions] extends {
- Insert: infer I
- }
- ? I
- : never
+ : PublicTableNameOrOptions extends keyof PublicSchema['Tables']
+ ? PublicSchema['Tables'][PublicTableNameOrOptions] extends {
+ Insert: infer I;
+ }
+ ? I
: never
+ : never;
export type TablesUpdate<
PublicTableNameOrOptions extends
- | keyof PublicSchema["Tables"]
+ | keyof PublicSchema['Tables']
| { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
- ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"]
+ ? keyof Database[PublicTableNameOrOptions['schema']]['Tables']
: never = never,
> = PublicTableNameOrOptions extends { schema: keyof Database }
- ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends {
- Update: infer U
+ ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends {
+ Update: infer U;
}
? U
: never
- : PublicTableNameOrOptions extends keyof PublicSchema["Tables"]
- ? PublicSchema["Tables"][PublicTableNameOrOptions] extends {
- Update: infer U
- }
- ? U
- : never
+ : PublicTableNameOrOptions extends keyof PublicSchema['Tables']
+ ? PublicSchema['Tables'][PublicTableNameOrOptions] extends {
+ Update: infer U;
+ }
+ ? U
: never
+ : never;
export type Enums<
PublicEnumNameOrOptions extends
- | keyof PublicSchema["Enums"]
+ | keyof PublicSchema['Enums']
| { schema: keyof Database },
EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database }
- ? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"]
+ ? keyof Database[PublicEnumNameOrOptions['schema']]['Enums']
: never = never,
> = PublicEnumNameOrOptions extends { schema: keyof Database }
- ? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName]
- : PublicEnumNameOrOptions extends keyof PublicSchema["Enums"]
- ? PublicSchema["Enums"][PublicEnumNameOrOptions]
- : never
+ ? Database[PublicEnumNameOrOptions['schema']]['Enums'][EnumName]
+ : PublicEnumNameOrOptions extends keyof PublicSchema['Enums']
+ ? PublicSchema['Enums'][PublicEnumNameOrOptions]
+ : never;
diff --git a/src/types/types.ts b/src/types/types.ts
index 5de02824..39e68620 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -7,6 +7,7 @@ Any updates to supabase.ts should be reflected here (new tables).
import { Database, Json } from './supabase';
export type DisplayRow = Database['public']['Tables']['displays']['Row'];
+export type LinksRow = Database['public']['Tables']['links']['Row'];
export type MediaRow = Database['public']['Tables']['media']['Row'];
export type TourDisplaysRow =
Database['public']['Tables']['tour_displays']['Row'];
diff --git a/tailwind.config.ts b/tailwind.config.ts
index d2cbeddb..c34d1fcb 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -19,6 +19,7 @@ const config: Config = {
shadow: '#808080',
silver: '#BDBDBD',
ivory: '#FFFDF7',
+ timberwolf: '#E2E2E2',
},
textColor: {
default: '#FFFDF7',
@@ -36,9 +37,6 @@ const config: Config = {
sans: ['Lato'],
lato: ['Lato'],
},
- screens: {
- web: '1024px',
- },
theme: {
fontSize: {
sm: ['14px', '20px'],