diff --git a/.gitignore b/.gitignore index a9d8fc7..24cdedf 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,4 @@ npm-debug.log* yarn-debug.log* -yarn-error.log* - -/public/question-bank.docx \ No newline at end of file +yarn-error.log* \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 9e5f59f..46fa3e1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,6 +9,7 @@ import Authentication from './pages/Authentication.tsx'; import { onAuthStateChanged } from 'firebase/auth'; import { auth } from './resources/Firebase.js'; import Strings from './resources/Strings.ts'; +import Stringify from './pages/Stringify.tsx'; const theme = extendTheme({}); @@ -53,6 +54,7 @@ function App() { background='var(--joy-palette-primary-100)' /> } /> + } /> diff --git a/src/pages/QuestionBank.tsx b/src/pages/QuestionBank.tsx index e17b803..9171f0c 100644 --- a/src/pages/QuestionBank.tsx +++ b/src/pages/QuestionBank.tsx @@ -1,6 +1,5 @@ import React, { ReactNode, useCallback, useEffect, useState } from "react"; import "./QuestionBank.css"; -import JSZip from "jszip"; import { DOMParser } from "@xmldom/xmldom"; import useDocumentTitle from "../hooks/useDocumentTitle.ts"; import { Alert, Button, CircularProgress, Link, Typography } from "@mui/joy"; @@ -8,17 +7,10 @@ import { onAuthStateChanged, sendEmailVerification } from "firebase/auth"; import { auth } from "../resources/Firebase.js"; import Paths from '../resources/Paths.ts'; -const str2xml = (str: string) => { - if (str.charCodeAt(0) === 65279) { - str = str.slice(1); - } - return new DOMParser().parseFromString(str, "text/xml"); -}; - -const getParagraphs = async (file: File) => { - const zip = new JSZip(); - const content = await zip.loadAsync(file); - const xml = str2xml(await content.file("word/document.xml")?.async("text") as string); +const parseQuestionBank = async (questionBank: string) => { + if (questionBank.charCodeAt(0) === 65279) + questionBank = questionBank.slice(1); + const xml = new DOMParser().parseFromString(questionBank, "text/xml"); const paragraphsXml = xml.getElementsByTagName("w:p"); const paragraphs: string[] = []; const stack: number[] = []; @@ -84,7 +76,7 @@ const QuestionBank: React.FC = ({ }) => { useDocumentTitle('My Answers'); /* verification */ - const [isSendingVerificationEmail, setIsSendingVerificationEmail] = useState(false); + const [isSendingVerificationEmail, setIsSendingVerificationEmail] = useState(true); const [sentVerificationEmail, setSentVerificationEmail] = useState(false); const [errorSendingVerificationEmail, setErrorSendingVerificationEmail] = useState(false); const [resendCount, setResendCount] = useState(0); @@ -131,7 +123,8 @@ const QuestionBank: React.FC = ({ }) => { { ); /* subscription */ - const [subscriptionChecked, setSubscriptionChecked] = useState(false); - const [subscriptionWillRenew, setSubscriptionWillRenew] = useState(); + const [subscriptionPortalUrl, setSubscriptionPortalUrl] = useState(null); + const [subscriptionCancelAtPeriodEnd, setSubscriptionCancelAtPeriodEnd] = useState(); const [subscriptionExpiryDate, setSubscriptionExpiryDate] = useState(); + const [questionBank, setQuestionBank] = useState([]); + const checkSubscription = useCallback(async () => { try { const response = await fetch(Paths.Serverless + '?user-uid=' + auth.currentUser?.uid); if (response.status === 200) { - const timestamp = await response.text(); + const data = JSON.parse(await response.text()); + + setSubscriptionPortalUrl(data['url']); + + setSubscriptionCancelAtPeriodEnd(data['cancel_at_period_end']); + + const timestamp = data['current_period_end']; const timestampInt = parseInt(timestamp, 10); - setSubscriptionChecked(true); setSubscriptionExpiryDate(new Date(timestampInt * 1000)); + + setQuestionBank(await parseQuestionBank(data['question-bank'])); } } catch (error) { - setSubscriptionChecked(true); console.error(error); } - }, [setSubscriptionChecked, setSubscriptionExpiryDate]); + }, [setSubscriptionPortalUrl, setSubscriptionCancelAtPeriodEnd, setSubscriptionExpiryDate, setQuestionBank]); useEffect(() => { checkSubscription(); }, [checkSubscription]); + const subscriptionWasChecked = subscriptionPortalUrl !== null const hasSubscriptionExpired = subscriptionExpiryDate && (subscriptionExpiryDate < new Date(Date.now())); - const willSubscriptionExpireThisWeek = !subscriptionWillRenew && subscriptionExpiryDate && (subscriptionExpiryDate < new Date(Date.now() + (7 * 86400000))); - - /* parse data */ - const [paragraphs, setParagraphs] = useState([]); - - const onFileUpload = useCallback(async () => { - try { - const response = await fetch('/question-bank.docx'); - const blob = await response.blob(); - const file = new File([blob], 'question-bank.docx', { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); - const paragraphs = await getParagraphs(file); - setParagraphs(paragraphs); - } catch (error) { - console.error(error); - } - }, []); - - useEffect(() => { - onFileUpload(); - }, [onFileUpload]); + const willSubscriptionExpireThisWeek = !subscriptionCancelAtPeriodEnd && subscriptionExpiryDate && (subscriptionExpiryDate < new Date(Date.now() + (7 * 86400000))); return (
{!emailVerified && ( - - - Please verify your email address using the link we've sent you.{" "} - {resendVerificationEmail} + + + Please verify your email address using the link we've sent you. {resendVerificationEmail} )} {subscriptionExpiryDate && ( <> - - Your subscription {hasSubscriptionExpired ? 'expired' : (subscriptionWillRenew ? 'will renew' : 'will expire')} at { + + Your subscription {hasSubscriptionExpired ? 'expired' : (subscriptionCancelAtPeriodEnd ? 'will expire' : 'will renew')} at { subscriptionExpiryDate && ( subscriptionExpiryDate.toLocaleString('en-GB', { hour: 'numeric', @@ -234,16 +210,15 @@ const QuestionBank: React.FC = ({ }) => { month: 'long', year: 'numeric' })) - }. - {subscriptionWillRenew && Cancel Renewal.} + }. {subscriptionPortalUrl && <> { window.location.href = subscriptionPortalUrl }}>{subscriptionCancelAtPeriodEnd ? 'Renew' : 'Cancel Renewal'}.} - {paragraphs.map((paragraph, index) => ( + {questionBank.map((paragraph, index) => (
{paragraph}
))} )} - {subscriptionChecked + {subscriptionWasChecked ? (!subscriptionExpiryDate || hasSubscriptionExpired) &&