diff --git a/components/page.js b/components/page.js
index 8ac236da..50582f3b 100644
--- a/components/page.js
+++ b/components/page.js
@@ -5,8 +5,6 @@ import { COLOR } from '../constants'
import Navbar from './navbar'
import Sidebar from './sidebar'
import HackerAppNavbar from './hackerAppNavbar'
-import Button from './button'
-import Icon from './Icon'
const HeaderContainer = styled.div`
display: flex;
@@ -43,12 +41,6 @@ const StyledHackerAppSection = styled.div`
gap: 75px;
`
-const StyledButton = styled(Button)`
- display: flex;
- align-items: center;
- gap: 10px;
-`
-
const StyledHackerAppNav = styled.div`
display: flex;
align-items: center;
@@ -84,14 +76,6 @@ export default ({
Hacker Application / {hackerAppHeader}
{loading && }
-
-
- Save
-
-
+
setToggled(!isToggled)}>
@@ -166,17 +166,17 @@ const QuestionCard = ({ question, removeQuestion, id, moveUp, moveDown, handleCh
Question
handleChange(id, 'title', e.target.value)}
/>
Description (optional)
handleChange(id, 'description', e.target.value)}
/>
Question Type
- handleChange(id, 'type', o)} defaultValue={question.type} />
+ handleChange(id, 'type', o)} defaultValue={question.type || ''} />
>
)}
{isToggled &&
@@ -186,7 +186,7 @@ const QuestionCard = ({ question, removeQuestion, id, moveUp, moveDown, handleCh
Options
- {question.options.map((option, index) => (
+ {(question.options || []).map((option, index) => (
Add Other
handleChange(id, 'other', !question.other)}
/>
@@ -215,7 +215,7 @@ const QuestionCard = ({ question, removeQuestion, id, moveUp, moveDown, handleCh
{isToggled && (
handleChange(id, 'required', !question.required)}
/>
diff --git a/pages/hackerapps/[id]/basicinfo.js b/pages/hackerapps/[id]/basicinfo.js
index 59bb939a..03d801d0 100644
--- a/pages/hackerapps/[id]/basicinfo.js
+++ b/pages/hackerapps/[id]/basicinfo.js
@@ -1,10 +1,21 @@
-import React, { useState } from 'react'
+import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
-import { getHackathonPaths, getHackathons } from '../../../utility/firebase'
+import {
+ getHackerAppQuestions,
+ getHackathonPaths,
+ getHackathons,
+ updateHackerAppQuestions,
+ getHackerAppQuestionsMetadata,
+ formatDate,
+ getTimestamp,
+ updateHackerAppQuestionsMetadata,
+} from '../../../utility/firebase'
import Page from '../../../components/page'
import { HACKER_APP_NAVBAR, COLOR } from '../../../constants'
import QuestionCard from '../../../components/questionCard'
import Icon from '../../../components/Icon'
+import Button from '../../../components/button'
+import { useAuth } from '../../../utility/auth'
const HeaderContainer = styled.div`
display: flex;
@@ -36,10 +47,41 @@ const QuestionsContainer = styled.div`
gap: 10px;
`
+const StyledButton = styled(Button)`
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ position: absolute;
+ top: 60px;
+ right: 80px;
+`
+
+const StyledMetadataP = styled.p`
+ position: absolute;
+ top: 100px;
+ right: 80px;
+ color: ${COLOR.MIDNIGHT_PURPLE};
+`
+
export default ({ id, hackathons }) => {
const [questions, setQuestions] = useState([
{ title: '', description: '', type: '', options: [''], other: false, required: false },
])
+ const [metadata, setMetadata] = useState({})
+ const { email: user } = useAuth().user
+
+ useEffect(() => {
+ const fetchQuestions = async () => {
+ const appQuestions = await getHackerAppQuestions(id, 'BasicInfo')
+ setQuestions(appQuestions)
+ }
+ const fetchMetadata = async () => {
+ const fetchedMetadata = await getHackerAppQuestionsMetadata(id, 'BasicInfo')
+ setMetadata(fetchedMetadata)
+ }
+ fetchQuestions()
+ fetchMetadata()
+ }, [id])
const addQuestion = index => {
const newQuestions = [...questions]
@@ -88,6 +130,14 @@ export default ({ id, hackathons }) => {
setQuestions(newQuestions)
}
+ const handleSave = async hackathon => {
+ await updateHackerAppQuestions(hackathon, questions, 'BasicInfo')
+ const newMetadata = { lastEditedAt: getTimestamp(), lastEditedBy: user }
+ setMetadata(newMetadata)
+ await updateHackerAppQuestionsMetadata(hackathon, 'BasicInfo', newMetadata)
+ alert('Questions were saved to the database!')
+ }
+
return (
<>
{
hackerAppHeader={id}
hackerAppNavbarItems={HACKER_APP_NAVBAR}
>
+ {
+ await handleSave(id)
+ }}
+ >
+
+ Save
+
+ {`Last Edited by ${metadata.lastEditedBy} at ${formatDate(
+ metadata.lastEditedAt?.seconds
+ )}`}
2. Add basic information questions
diff --git a/pages/hackerapps/[id]/skills.js b/pages/hackerapps/[id]/skills.js
index d7c1fba4..832c9e9a 100644
--- a/pages/hackerapps/[id]/skills.js
+++ b/pages/hackerapps/[id]/skills.js
@@ -1,10 +1,21 @@
-import React, { useState } from 'react'
+import React, { useState, useEffect } from 'react'
import styled from 'styled-components'
-import { getHackathonPaths, getHackathons } from '../../../utility/firebase'
+import {
+ getHackathonPaths,
+ getHackathons,
+ getHackerAppQuestions,
+ updateHackerAppQuestions,
+ getHackerAppQuestionsMetadata,
+ formatDate,
+ getTimestamp,
+ updateHackerAppQuestionsMetadata,
+} from '../../../utility/firebase'
import Page from '../../../components/page'
import { HACKER_APP_NAVBAR, COLOR } from '../../../constants'
import QuestionCard from '../../../components/questionCard'
import Icon from '../../../components/Icon'
+import Button from '../../../components/button'
+import { useAuth } from '../../../utility/auth'
const HeaderContainer = styled.div`
display: flex;
@@ -36,10 +47,41 @@ const QuestionsContainer = styled.div`
gap: 10px;
`
+const StyledButton = styled(Button)`
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ position: absolute;
+ top: 60px;
+ right: 80px;
+`
+
+const StyledMetadataP = styled.p`
+ position: absolute;
+ top: 100px;
+ right: 80px;
+ color: ${COLOR.MIDNIGHT_PURPLE};
+`
+
export default ({ id, hackathons }) => {
const [questions, setQuestions] = useState([
{ title: '', description: '', type: '', options: [''], other: false, required: false },
])
+ const [metadata, setMetadata] = useState({})
+ const { email: user } = useAuth().user
+
+ useEffect(() => {
+ const fetchQuestions = async () => {
+ const appQuestions = await getHackerAppQuestions(id, 'Skills')
+ setQuestions(appQuestions)
+ }
+ const fetchMetadata = async () => {
+ const fetchedMetadata = await getHackerAppQuestionsMetadata(id, 'Skills')
+ setMetadata(fetchedMetadata)
+ }
+ fetchQuestions()
+ fetchMetadata()
+ }, [id])
const addQuestion = index => {
const newQuestions = [...questions]
@@ -88,6 +130,14 @@ export default ({ id, hackathons }) => {
setQuestions(newQuestions)
}
+ const handleSave = async hackathon => {
+ await updateHackerAppQuestions(hackathon, questions, 'Skills')
+ const newMetadata = { lastEditedAt: getTimestamp(), lastEditedBy: user }
+ setMetadata(newMetadata)
+ await updateHackerAppQuestionsMetadata(hackathon, 'Skills', newMetadata)
+ alert('Questions were saved to the database!')
+ }
+
return (
<>
{
hackerAppHeader={id}
hackerAppNavbarItems={HACKER_APP_NAVBAR}
>
+ {
+ await handleSave(id)
+ }}
+ >
+
+ Save
+
+ {`Last Edited by ${metadata.lastEditedBy} at ${formatDate(
+ metadata.lastEditedAt?.seconds
+ )}`}
3. Add skills and long answer questions
diff --git a/pages/hackerapps/[id]/welcome.js b/pages/hackerapps/[id]/welcome.js
index 53683f7b..fb42fb5a 100644
--- a/pages/hackerapps/[id]/welcome.js
+++ b/pages/hackerapps/[id]/welcome.js
@@ -1,10 +1,22 @@
import dynamic from 'next/dynamic'
-import React, { useState } from 'react'
+import React, { useState, useEffect } from 'react'
import styled from 'styled-components'
import TextField from '../../../components/TextField'
import Page from '../../../components/page'
import { COLOR, HACKER_APP_NAVBAR } from '../../../constants'
-import { getHackathonPaths, getHackathons } from '../../../utility/firebase'
+import {
+ getHackathonPaths,
+ getHackathons,
+ updateHackerAppQuestions,
+ getHackerAppQuestions,
+ getHackerAppQuestionsMetadata,
+ formatDate,
+ getTimestamp,
+ updateHackerAppQuestionsMetadata,
+} from '../../../utility/firebase'
+import Button from '../../../components/button'
+import Icon from '../../../components/Icon'
+import { useAuth } from '../../../utility/auth'
const ReactQuill = dynamic(() => import('react-quill'), { ssr: false })
@@ -46,6 +58,22 @@ const Header = styled.h1`
color: ${COLOR.MIDNIGHT_PURPLE_DEEP};
`
+const StyledButton = styled(Button)`
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ position: absolute;
+ top: 60px;
+ right: 80px;
+`
+
+const StyledMetadataP = styled.p`
+ position: absolute;
+ top: 100px;
+ right: 80px;
+ color: ${COLOR.MIDNIGHT_PURPLE};
+`
+
const descModules = {
toolbar: [
['bold', 'italic', 'underline', 'strike', 'blockquote'],
@@ -59,6 +87,33 @@ const formats = ['bold', 'italic', 'underline', 'strike', 'blockquote', 'list',
export default ({ id, hackathons }) => {
const [title, setTitle] = useState('')
+ const [content, setContent] = useState('')
+ const [metadata, setMetadata] = useState({})
+ const { email: user } = useAuth().user
+
+ useEffect(() => {
+ const fetchQuestions = async () => {
+ const questions = await getHackerAppQuestions(id, 'Welcome')
+ setTitle(questions[0].title || '')
+ setContent(questions[0].content || '')
+ }
+ const fetchMetadata = async () => {
+ const fetchedMetadata = await getHackerAppQuestionsMetadata(id, 'Welcome')
+ setMetadata(fetchedMetadata)
+ }
+ fetchQuestions()
+ fetchMetadata()
+ }, [id])
+
+ const handleSave = async hackathon => {
+ const questions = [{ title: title, content: content }]
+ await updateHackerAppQuestions(hackathon, questions, 'Welcome')
+ const newMetadata = { lastEditedAt: getTimestamp(), lastEditedBy: user }
+ setMetadata(newMetadata)
+ await updateHackerAppQuestionsMetadata(hackathon, 'Welcome', newMetadata)
+ alert('Questions were saved to the database!')
+ }
+
return (
<>
{
hackerAppHeader={id}
hackerAppNavbarItems={HACKER_APP_NAVBAR}
>
+ {
+ await handleSave(id)
+ }}
+ >
+
+ Save
+
+ {`Last Edited by ${metadata.lastEditedBy} at ${formatDate(
+ metadata.lastEditedAt?.seconds
+ )}`}
1. Add a title and description
@@ -77,7 +146,14 @@ export default ({ id, hackathons }) => {
customValue={title}
onChangeCustomValue={e => setTitle(e.target.value)}
/>
-
+
>
diff --git a/utility/firebase.js b/utility/firebase.js
index c4ee2f8f..b8e9aa25 100644
--- a/utility/firebase.js
+++ b/utility/firebase.js
@@ -746,3 +746,42 @@ export const updateApplicantTags = async (userId, applicantTags) => {
.doc(userId)
.update({ applicantTags })
}
+
+// hacker application questions specific
+export const getHackerAppQuestions = async (selectedHackathon, category) => {
+ const data = await db.collection('HackerAppQuestions').doc(selectedHackathon.slice(0, -4)).collection(category).get()
+ return data.docs.map(doc => doc.data())
+}
+
+export const updateHackerAppQuestions = async (selectedHackathon, questions, category) => {
+ const hackathonRef = db.collection('HackerAppQuestions').doc(selectedHackathon.slice(0, -4))
+ const categoryRef = hackathonRef.collection(category)
+
+ const batch = db.batch()
+
+ // clear all
+ const existingDocs = await categoryRef.get()
+ existingDocs.forEach(doc => {
+ batch.delete(doc.ref)
+ })
+
+ questions.forEach((question, index) => {
+ const newDocRef = categoryRef.doc(`${index.toString().padStart(3, '0')}`)
+ batch.set(newDocRef, question)
+ })
+ await batch.commit()
+}
+
+export const getHackerAppQuestionsMetadata = async (selectedHackathon, category) => {
+ const categoryRef = await db.collection('HackerAppQuestions').doc(selectedHackathon.slice(0, -4)).get()
+ return categoryRef.data()[category]
+}
+
+export const updateHackerAppQuestionsMetadata = async (selectedHackathon, category, updatedMetadata) => {
+ const doc = {
+ [category]: updatedMetadata,
+ }
+ return db.collection('HackerAppQuestions').doc(selectedHackathon.slice(0, -4)).set(doc, { merge: true })
+}
+
+// hacker application questions specific end