Skip to content

Commit

Permalink
Merge pull request #15 from Ryczko/feature/load-survey-data-from-backend
Browse files Browse the repository at this point in the history
Load survey answers data from backend
  • Loading branch information
Ryczko authored Apr 28, 2022
2 parents 95cd3d4 + cf61e06 commit d94b8af
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 85 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ module.exports = {
quotes: ['error', 'single'],
semi: ['error', 'always'],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off'
},
};
23 changes: 5 additions & 18 deletions src/Components/AnswerHeader/index.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,22 @@
import React from 'react';

interface AnswerHeaderProps {
totalVotes: number;
medianOfScore: string;
startTime: string;
endTime: string;
}

function AnswerHeader({
totalVotes,
medianOfScore,
startTime,
endTime,
}: AnswerHeaderProps & React.HTMLProps<HTMLButtonElement>) {
function AnswerHeader({ totalVotes, startTime }: AnswerHeaderProps) {
return (
<div className="flex flex-col items-center justify-center py-4">
<table className="table-auto">
<thead>
<tr>
<th className="p-4">Total Votes</th>
<th className="p-4">Median of score</th>
<th className="p-4">Start Time</th>
<th className="p-4">End Time</th>
<th className="py-2 px-8">Total Votes</th>
<th className="py-2 px-8">Start Time</th>
</tr>
</thead>
<tbody>
<tr>
<td className="p-4">{totalVotes}</td>
<td className="p-4">{medianOfScore}</td>
<td className="p-4">{startTime}</td>
<td className="p-4">{endTime}</td>
<td className="py-2 px-8">{totalVotes}</td>
<td className="py-2 px-8">{startTime}</td>
</tr>
</tbody>
</table>
Expand Down
11 changes: 1 addition & 10 deletions src/Components/AnswerTable/index.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
import { DownloadIcon } from '@heroicons/react/outline';
import React from 'react';
import IconButton, { IconButtonVariant } from '../../Components/IconButton';

function AnswerTable({ children }: React.HTMLProps<HTMLButtonElement>) {
return (
<div className="flex flex-col items-center justify-center py-4">
<table className="table-auto w:4/6 sm:w-3/4 drop-shadow-lg">
<thead>
<tr>
<th className="p-8">ID</th>
<th className="p-8">Time</th>
<th className="p-8">Score</th>
<th className="w-1/3 p-8">Text</th>
<th className="hidden px-8 sm:table-cell">
<IconButton
variant={IconButtonVariant.PRIMARY}
icon={<DownloadIcon className="w-5 h-5" />}
></IconButton>
</th>
<th className="w-1/2 p-8">Text</th>
</tr>
</thead>
<tbody>{children}</tbody>
Expand Down
16 changes: 3 additions & 13 deletions src/Components/AnswerTableRow/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
import React from 'react';

interface AnswerTableRowProps {
ID: number;
time: string;
score: string;
selectedIcon: string;
text: string;
}

function AnswerTableRow({
ID,
time,
score,
text,
}: AnswerTableRowProps & React.HTMLProps<HTMLButtonElement>) {
function AnswerTableRow({ time, selectedIcon, text }: AnswerTableRowProps) {
return (
<tr className="bg-white sm:py-4 text-zinc-500">
<td className="sm:p-4">{ID}</td>
<td className="sm:p-4">{time}</td>
<td className="sm:p-4">{score}</td>
<td className="sm:p-4">{selectedIcon}</td>
<td className="sm:p-4">{text}</td>
<td className="hidden sm:p-2 sm:table-cell"></td>
</tr>
);
}
Expand Down
5 changes: 3 additions & 2 deletions src/Components/ProtectedRoute/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ type ProtectedRouteProps = {

const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
const [user, loading, error] = useAuthState(auth);
const isLoggedIn = user && !loading && !error;
const isLoggedIn = user && !error;
const location = useLocation();

if (loading) return null;
if (!isLoggedIn) {
return <Navigate to="/login" state={{ from: location }} replace />;
} else {
return children;
}
};

export default ProtectedRoute;
export default ProtectedRoute;
8 changes: 3 additions & 5 deletions src/Pages/PageWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { lazy, Suspense } from 'react';
import { Routes, Route, BrowserRouter, Navigate } from 'react-router-dom';
import { Routes, Route, BrowserRouter } from 'react-router-dom';
import ProtectedRoute from '../Components/ProtectedRoute';
import Navigation from '../Layouts/Navigation';
import HomePage from './HomePage';
Expand Down Expand Up @@ -45,20 +45,18 @@ function PageWrapper() {
}
/>
<Route
path="/survey/answer/:answerId"
path="/survey/answer/:surveyId"
element={
<ProtectedRoute>
<SurveyAnswerPage />
</ProtectedRoute>
}
/>

<Route path="*" element={<Navigate to="/" />} />
</Routes>
</Suspense>
</div>
</BrowserRouter>
);
}

export default PageWrapper;
export default PageWrapper;
114 changes: 83 additions & 31 deletions src/Pages/SurveyAnswerPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,83 @@ import AnswerHeader from '../../Components/AnswerHeader';
import AnswerTableRow from '../../Components/AnswerTableRow';
import IconButton, { IconButtonVariant } from '../../Components/IconButton';
import { LinkIcon } from '@heroicons/react/outline';
import { useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom';
import { useDocumentTitle } from '../../Hooks/useDocumentTitle';
import { useEffect, useState } from 'react';
import { db } from '../../firebase';
import {
collection,
doc,
getDoc,
getDocs,
Timestamp,
} from 'firebase/firestore';

interface AnswerData {
id: string;
answerDate: string;
selectedIcon: string;
answer: string;
}

function SurveyAnswerPage() {
useDocumentTitle('Survey Answers');
const { answerId } = useParams();
const { surveyId } = useParams();
const navigate = useNavigate();

const [votes, setVotes] = useState(0);
const [title, setTitle] = useState('');
const [startTime, setStartTime] = useState('-');
const [answersData, setAnswersData] = useState<AnswerData[]>([]);

useEffect(() => {
if (!surveyId) {
navigate('/');
return;
}

getSurveyData();
}, [surveyId]);

const getSurveyData = async () => {
const surveyData = await getDoc(doc(db, 'surveys', surveyId!));
if (!surveyData.exists()) {
navigate('/');
return;
}

const answersData = await getDocs(
collection(db, 'surveys', surveyId!, 'answers')
);
setVotes(answersData.docs.length);

setStartTime(
formatFirebaseDate(surveyData.data()?.createdDate as Timestamp)
);
setTitle(surveyData.data()?.title);
const data = answersData.docs.map((doc) => ({
...doc.data(),
answerDate: formatFirebaseDate(doc.data().answerDate as Timestamp),
})) as AnswerData[];

setAnswersData(data);
};

const formatFirebaseDate = (date: Timestamp) => {
return date.toDate().toLocaleString('pl-PL', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
});
};

return (
<div className="container block px-4 mx-auto mt-10 text-center">
<div className="flex flex-row justify-center mb-10">
<h1 className="mx-4 text-4xl font-bold text-center">
Answers for {answerId}
Answers for &quot;{title}&quot;
</h1>
<IconButton
title="Copy link to clipboard"
Expand All @@ -23,34 +88,21 @@ function SurveyAnswerPage() {
icon={<LinkIcon className="w-5 h-5" />}
/>
</div>
<AnswerHeader
totalVotes={120}
medianOfScore={'3/4'}
startTime={'12:30:00'}
endTime={'12:45:00'}
/>
<AnswerTable>
<AnswerTableRow
ID={1}
time={'12:41:04'}
score={'1/4'}
text={'TEST TEST TEST'}
/>
<AnswerTableRow
ID={1}
time={'12:41:04'}
score={'1/4'}
text={
'TEST TEST TESTTEST TEST TESTTEST TEST TESTTEST TEST TESTTEST TEST TESTTEST TEST TESTTEST TEST TESTTEST TEST TESTTEST TEST TESTTEST TEST TEST'
}
/>
<AnswerTableRow
ID={1}
time={'12:41:04'}
score={'1/4'}
text={'TEST TEST TEST'}
/>
</AnswerTable>
<AnswerHeader totalVotes={votes} startTime={startTime} />
{answersData.length > 0 ? (
<AnswerTable>
{answersData.map((answer) => (
<AnswerTableRow
key={answer.id}
time={answer.answerDate}
selectedIcon={answer.selectedIcon}
text={answer.answer}
/>
))}
</AnswerTable>
) : (
<div className="mt-8">No answers yet</div>
)}
</div>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Pages/SurveyListPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function SurveyListPage() {
};

const handleOnMoreButton = (id: string) => () => {
navigate(`/survey/${id}`);
navigate(`/survey/answer/${id}`);
};

return (
Expand Down
6 changes: 1 addition & 5 deletions src/Pages/SurveyPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,7 @@ function SurveyPage() {
}, [surveyId]);

const getSurveyData = async () => {
if (!surveyId) {
navigate('/');
return;
}
const surveyData = await getDoc(doc(db, 'surveys', surveyId));
const surveyData = await getDoc(doc(db, 'surveys', surveyId!));
if (!surveyData.exists()) {
navigate('/');
return;
Expand Down

0 comments on commit d94b8af

Please sign in to comment.