diff --git a/constants.js b/constants.js
index 8eb245ea..e9796f3e 100644
--- a/constants.js
+++ b/constants.js
@@ -31,6 +31,7 @@ export const HACKATHON_NAVBAR = {
intro: 'Intro',
events: 'Events',
spocos: 'Sponsors',
+ resources: 'Resources',
FeatureFlags: 'Feature Flags',
BuildConfig: 'Build Config',
};
diff --git a/pages/[id]/resources.js b/pages/[id]/resources.js
new file mode 100644
index 00000000..6d4fc356
--- /dev/null
+++ b/pages/[id]/resources.js
@@ -0,0 +1,325 @@
+import { useState, useEffect, createRef } from 'react';
+import Page from '../../components/page';
+import Button from '../../components/button';
+import Card, {
+ CardHeader,
+ CardTitle,
+ CardContent,
+ CardButtonContainer,
+} from '../../components/card';
+import Checkbox from '../../components/checkbox';
+import {
+ TableWrapper,
+ TableContent,
+ TableRow,
+ TableHeader,
+ TableData,
+ ActionsButtonContainer,
+} from '../../components/table';
+import Modal, {
+ ModalContent,
+ ModalField,
+ LogoImage,
+ UploadContainer,
+} from '../../components/modal';
+import {
+ getHackathonPaths,
+ getHackathons,
+ setDocument,
+ uploadResourceImageToStorage,
+ getAllResources,
+ deleteDocument,
+} from '../../utility/firebase';
+import { EDIT, NEW, DELETE, COLOR, HACKATHON_NAVBAR } from '../../constants';
+
+const RESOURCES = 'Resources';
+
+export default function Resources({ id, hackathons }) {
+ const [resourceToEdit, setResourceToEdit] = useState(false);
+ const [resources, setResources] = useState([]);
+
+ const addNewResourceCard = async () => {
+ setResourceToEdit({ id: Date.now().toString() });
+ };
+
+ const handleEdit = (r) => {
+ setResourceToEdit(r);
+ };
+
+ const handleDelete = (rId) => {
+ deleteDocument(id, RESOURCES, rId);
+ };
+
+ const finishUpdate = ({ id: rId, ...resource }) => {
+ setDocument(id, RESOURCES, rId, resource);
+ };
+
+ useEffect(() => {
+ const getResources = async () => getAllResources(id, setResources);
+ getResources();
+ }, [resourceToEdit]);
+
+ return (
+
+ {id === 'www' ? (
+
+
+ Resources
+
+
+
+
+
+
+
+
+
+ {resources.map((r) => (
+ handleDelete(r.id)}
+ {...r}
+ />
+ ))}
+
+
+
+
+
+
+ ) : (
+
+
+ Not applicable for this website
+
+
+ )}
+
+ );
+}
+
+const EditModal = ({ resourceToEdit, setResourceToEdit, finishUpdate }) => {
+ const [resource, setResource] = useState(resourceToEdit);
+ const [imgObject, setImgObject] = useState({});
+ const inputFile = createRef();
+
+ const handleUpdate = async () => {
+ // Don't judge
+ await new Promise((r) => setTimeout(r, 500));
+ finishUpdate({
+ id: resource.id,
+ title: resource.title || '',
+ imageUrl: resource.imageUrl || '',
+ resourceUrl: resource.resourceUrl || '',
+ event: resource.event || '',
+ year: resource.year || 0,
+ isOurPick: resource.isOurPick || false,
+ type: resource.type || '',
+ });
+ setResourceToEdit({});
+ };
+
+
+ const handleInput = (property, value) => {
+ setResource({
+ ...resource,
+ [property]: value,
+ });
+ };
+
+ const uploadImage = async (imgUrl) => {
+ const imageUrl = await uploadResourceImageToStorage(resource.id, imgUrl);
+ handleInput('imageUrl', imageUrl);
+ };
+
+ // clicks the invisible
+
+
+
+ {
+ handleInput('resourceUrl', e.target.value);
+ }}
+ />
+
+
+
+ {
+ handleInput('event', e.target.value);
+ }}
+ />
+ {
+ handleInput('year', e.target.value);
+ }}
+ />
+ {
+ handleInput('type', e.target.value);
+ }}
+ />
+
+
+
+ {
+ handleInput('isOurPick', !resource.isOurPick);
+ }}
+ />
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const CustomTableHeader = () => (
+
+
+ Title
+ Image Url
+ Resource Url
+ Event
+ Type
+ Year
+ Our pick?
+ Actions
+
+
+);
+
+const ResourceRow = ({ handleEdit, handleDelete, ...props }) => {
+ return (
+
+ {props.title}
+ {props.imageUrl}
+ {props.resourceUrl}
+ {props.event}
+ {props.type}
+ {props.year}
+ {props.isOurPick?.toString() || false}
+
+
+
+
+
+
+
+ );
+};
+
+export const getStaticPaths = async () => {
+ return getHackathonPaths();
+};
+
+export const getStaticProps = async ({ params }) => {
+ const hackathons = await getHackathons();
+ return {
+ props: {
+ hackathons,
+ id: params.id,
+ },
+ };
+};
diff --git a/utility/firebase.js b/utility/firebase.js
index a814d363..db0a603b 100644
--- a/utility/firebase.js
+++ b/utility/firebase.js
@@ -70,7 +70,7 @@ export const getDocument = async (hackathon, collection) => {
};
export const updateDocument = (hackathon, collection, docId, object) => {
- db.collection(webCollection)
+ db.collection(Hackathons)
.doc(hackathon)
.collection(collection)
.doc(docId)
@@ -79,7 +79,7 @@ export const updateDocument = (hackathon, collection, docId, object) => {
export const addDocument = async (hackathon, collection, object) => {
const ref = await db
- .collection(webCollection)
+ .collection(Hackathons)
.doc(hackathon)
.collection(collection)
.add(object);
@@ -88,13 +88,22 @@ export const addDocument = async (hackathon, collection, object) => {
export const deleteDocument = async (hackathon, collection, docId) => {
await db
- .collection(webCollection)
+ .collection(Hackathons)
.doc(hackathon)
.collection(collection)
.doc(docId)
.delete();
};
+export const setDocument = async (hackathon, collection, docId, object) => {
+ await db
+ .collection(Hackathons)
+ .doc(hackathon)
+ .collection(collection)
+ .doc(docId)
+ .set(object);
+};
+
export const getHackathons = async () => {
return db
.collection('Hackathons')
@@ -770,3 +779,32 @@ export const updateApplicantStatus = async (userId, applicationStatus) => {
'status.applicationStatus': applicationStatus,
});
};
+
+export const uploadResourceImageToStorage = async (id, file) => {
+ try {
+ const ref = storage.ref(`resource/${id}/${file.name}`);
+ const uploadData = await ref.put(file);
+ return uploadData.ref.getDownloadURL();
+ } catch (e) {
+ // eslint-disable-next-line no-alert
+ alert(e);
+ return null;
+ }
+};
+
+export const getAllResources = async (website, callback) => {
+ return db
+ .collection('Hackathons')
+ .doc(website) // hardcode for event
+ .collection('Resources')
+ .onSnapshot((snap) => {
+ callback(
+ snap.docs.map((doc) => {
+ return {
+ id: doc.id,
+ ...doc.data(),
+ };
+ })
+ );
+ });
+};