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