diff --git a/src/components/StandardNav.jsx b/src/components/StandardNav.jsx
index 7e9c37a3..23f67f28 100644
--- a/src/components/StandardNav.jsx
+++ b/src/components/StandardNav.jsx
@@ -1,6 +1,5 @@
-import { Fragment, useEffect, useState } from 'react';
-import { Disclosure, Menu, Popover, Transition } from '@headlessui/react';
-import { Dialog } from '@headlessui/react';
+import { Fragment, useEffect, useState, useContext } from 'react'
+import { Disclosure, Menu, Popover, Transition, Dialog } from '@headlessui/react'
import {
Bars3Icon,
@@ -12,259 +11,260 @@ import {
ArrowRightIcon,
EllipsisVerticalIcon,
ShieldCheckIcon,
- BellIcon,
-} from '@heroicons/react/24/outline';
-import { Logo } from '@/components/Logo';
-import Link from 'next/link';
-import request from '@/utils/request';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faEllipsis, faSearch } from '@fortawesome/free-solid-svg-icons';
+ BellIcon
+} from '@heroicons/react/24/outline'
+import { Logo } from '@/components/Logo'
+import Link from 'next/link'
+import request from '@/utils/request'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import {
+ faEllipsis, faSearch,
faBug,
faLock,
faUserSecret,
faNetworkWired,
faBrain,
- faTerminal,
-} from '@fortawesome/free-solid-svg-icons';
-
-import 'reactjs-popup/dist/index.css';
-import Upgrade from './nav/Upgrade';
-
-import { useRouter } from 'next/router';
-import { LogoAdmin } from './LogoAdmin';
-import { CSSTransition } from 'react-transition-group';
-import SearchModal from './nav/SearchModal';
-import SpawnTerminal from './nav/SpawnTerminal';
-import { Context } from '@/context';
-import { useContext } from 'react';
-
-function classNames(...classes) {
- return classes.filter(Boolean).join(' ');
+ faTerminal
+} from '@fortawesome/free-solid-svg-icons'
+
+import 'reactjs-popup/dist/index.css'
+import Upgrade from './nav/Upgrade'
+
+import { useRouter } from 'next/router'
+import { LogoAdmin } from './LogoAdmin'
+import { CSSTransition } from 'react-transition-group'
+import SearchModal from './nav/SearchModal'
+import SpawnTerminal from './nav/SpawnTerminal'
+import { Context } from '@/context'
+
+function classNames (...classes) {
+ return classes.filter(Boolean).join(' ')
}
-const baseUrl = process.env.NEXT_PUBLIC_FRONTEND_URL;
-const adminList = ['pranav'];
+const baseUrl = process.env.NEXT_PUBLIC_FRONTEND_URL
+const adminList = ['pranav']
const DEFAULT_NOTIFICATION = {
image:
'https://cutshort-data.s3.amazonaws.com/cloudfront/public/companies/5809d1d8af3059ed5b346ed1/logo-1615367026425-logo-v6.png',
message: 'You have no notifications.',
detailPage: '/events',
- receivedTime: '',
-};
+ receivedTime: ''
+}
-export function StandardNav({ guestAllowed, alignCenter = true }) {
- const { role, points } = useContext(Context);
+export function StandardNav ({ guestAllowed, alignCenter = true }) {
+ const { role, points } = useContext(Context)
- const [terminaIsOpen, setTerminalIsOpen] = useState(false);
- const [upgradeModalOpen, setUpgradeModalOpen] = useState(false);
+ const [terminaIsOpen, setTerminalIsOpen] = useState(false)
+ const [upgradeModalOpen, setUpgradeModalOpen] = useState(false)
- const [isAdmin, setIsAdmin] = useState(true);
- const [notifications, setNotifications] = useState([]);
- const [showBanner, setShowBanner] = useState(false);
- const [showSearchModal, setShowSearchModal] = useState(false);
- const [isPopoverOpen, setIsPopoverOpen] = useState(false);
- const [showNotificationsDropdown, setShowNotificationsDropdown] = useState(false);
+ const [isAdmin, setIsAdmin] = useState(true)
+ const [notifications, setNotifications] = useState([])
+ const [showBanner, setShowBanner] = useState(false)
+ const [showSearchModal, setShowSearchModal] = useState(false)
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false)
+ const [showNotificationsDropdown, setShowNotificationsDropdown] = useState(false)
- const [open, setOpen] = useState(true);
+ const [open, setOpen] = useState(true)
- const router = useRouter();
+ const router = useRouter()
- function logout() {
+ function logout () {
document.cookie =
- 'idToken=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
- router.push('/login');
+ 'idToken=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
+ router.push('/login')
}
useEffect(() => {
if (!localStorage.getItem('dismissStatus')) {
- setShowBanner(true);
+ setShowBanner(true)
}
- }, []);
+ }, [])
// Function to close the modal
const closeModal = () => {
- setShowSearchModal(false);
- };
+ setShowSearchModal(false)
+ }
// Effect to add and remove the event listener
useEffect(() => {
const handleKeyDown = (event) => {
if (event.keyCode === 27) {
// 27 is the key code for ESC key
- closeModal();
+ closeModal()
}
- };
+ }
// Add event listener
- document.addEventListener('keydown', handleKeyDown);
+ document.addEventListener('keydown', handleKeyDown)
// Remove event listener on cleanup
return () => {
- document.removeEventListener('keydown', handleKeyDown);
- };
- }, []);
+ document.removeEventListener('keydown', handleKeyDown)
+ }
+ }, [])
const toggleSearchModal = () => {
- setShowSearchModal((prev) => !prev); // Toggle the state
- };
+ setShowSearchModal((prev) => !prev) // Toggle the state
+ }
- const [notification, showNotifications] = useState(false);
+ const [notification, showNotifications] = useState(false)
const [notificationData, setNotificationData] = useState([
- DEFAULT_NOTIFICATION,
- ]);
+ DEFAULT_NOTIFICATION
+ ])
- const [username, setUsername] = useState(null);
- const [pfp, setPfp] = useState(null);
+ const [username, setUsername] = useState(null)
+ const [pfp, setPfp] = useState(null)
// get user's profile picture
useEffect(() => {
if (!username) {
- return;
+ return
}
if (localStorage.getItem('pfp')) {
- setPfp(localStorage.getItem('pfp'));
+ setPfp(localStorage.getItem('pfp'))
}
const fetchData = async () => {
try {
const endPoint =
- process.env.NEXT_PUBLIC_API_URL + '/users/' + username + '/pfp';
- const result = await request(endPoint, 'GET', null);
+ process.env.NEXT_PUBLIC_API_URL + '/users/' + username + '/pfp'
+ const result = await request(endPoint, 'GET', null)
if (result) {
- setPfp(result);
+ setPfp(result)
} else {
- setPfp(`https://robohash.org/${username}.png?set=set1&size=150x150`);
+ setPfp(`https://robohash.org/${username}.png?set=set1&size=150x150`)
}
} catch (err) {
- console.log('failed to get profile picture');
+ console.log('failed to get profile picture')
}
- };
- fetchData();
- }, [username]);
+ }
+ fetchData()
+ }, [username])
useEffect(() => {
const fetchNotification = async () => {
- console.log('fetching notifications');
+ console.log('fetching notifications')
const endPoint =
- process.env.NEXT_PUBLIC_API_URL + '/account/notifications';
- const result = await request(endPoint, 'GET', null);
- if (!result || !result.length) return;
+ process.env.NEXT_PUBLIC_API_URL + '/account/notifications'
+ const result = await request(endPoint, 'GET', null)
+ if (!result || !result.length) return
- console.log('Here is the result');
- console.log(result);
+ console.log('Here is the result')
+ console.log(result)
setNotificationData(
result.map((notification) => {
- const currentDate = new Date();
- const createdAt = new Date(notification.createdAt);
- const timedelta = currentDate - createdAt;
- console.log(notification);
- let noti = '';
-
- let seconds = Math.floor(timedelta / 1000);
- let minutes = Math.floor(seconds / 60);
- seconds = seconds % 60;
- let hours = Math.floor(minutes / 60);
- minutes = minutes % 60;
- let days = Math.floor(hours / 24);
- hours = hours % 24;
-
- if (days) noti = days + ' days';
- else if (hours) noti = hours + ' hours';
- else if (minutes) noti = minutes + ' minutes';
- else noti = seconds = ' seconds';
+ const currentDate = new Date()
+ const createdAt = new Date(notification.createdAt)
+ const timedelta = currentDate - createdAt
+ console.log(notification)
+ let noti = ''
+
+ let seconds = Math.floor(timedelta / 1000)
+ let minutes = Math.floor(seconds / 60)
+ seconds = seconds % 60
+ let hours = Math.floor(minutes / 60)
+ minutes = minutes % 60
+ const days = Math.floor(hours / 24)
+ hours = hours % 24
+
+ if (days) noti = days + ' days'
+ else if (hours) noti = hours + ' hours'
+ else if (minutes) noti = minutes + ' minutes'
+ else noti = seconds = ' seconds'
return {
message: notification.message,
receivedTime: noti + ' ago',
detailPage: '/events',
image:
- 'https://cutshort-data.s3.amazonaws.com/cloudfront/public/companies/5809d1d8af3059ed5b346ed1/logo-1615367026425-logo-v6.png',
- };
+ 'https://cutshort-data.s3.amazonaws.com/cloudfront/public/companies/5809d1d8af3059ed5b346ed1/logo-1615367026425-logo-v6.png'
+ }
})
- );
- };
- setUsername(localStorage.getItem('username') || null);
- fetchNotification();
- }, []);
-
- function dismissStatus() {
- localStorage.setItem('dismissStatus', true);
- setShowBanner(false);
+ )
+ }
+ setUsername(localStorage.getItem('username') || null)
+ fetchNotification()
+ }, [])
+
+ function dismissStatus () {
+ localStorage.setItem('dismissStatus', true)
+ setShowBanner(false)
}
const fetchNotifications = async () => {
try {
- const url = `${process.env.NEXT_PUBLIC_API_URL}/notification`;
- const data = await request(url, 'GET', null);
- console.log(data);
+ const url = `${process.env.NEXT_PUBLIC_API_URL}/notification`
+ const data = await request(url, 'GET', null)
+ console.log(data)
if (data.success) {
- setNotifications(data.body);
- console.log(data);
+ setNotifications(data.body)
+ console.log(data)
} else {
- setNotifications(['Unable to get notification, try again']);
+ setNotifications(['Unable to get notification, try again'])
}
} catch (err) {
- console.log(err);
+ console.log(err)
}
- };
+ }
const linkClass = (path) =>
`inline-flex items-center border-b-2 px-4 pt-1 text-md transition-all ${
router.pathname === path
? 'text-blue-500 border-blue-500'
: 'text-gray-300 hover:text-gray-50 border-transparent'
- }`;
+ }`
return (
<>
{isPopoverOpen && (
setShowSearchModal(false)}
>
test
-
+
)}
-
+
{({ open }) => (
<>
-
-
-
+
+
+
{/* Mobile menu button */}
-
- Open main menu
- {open ? (
-
- ) : (
-
- )}
+
+ Open main menu
+ {open
+ ? (
+
+ )
+ : (
+
+ )}
-
-
+
+
-
+
{/* Ellipsis dropdown */}
-
+
{({ open }) => (
<>
-
+
-
-
-
+
+
+
-
+
Create
-
+
Classrooms
@@ -345,18 +345,18 @@ export function StandardNav({ guestAllowed, alignCenter = true }) {
)}
- {/*search bar*/}
-
+ {/* search bar */}
+
setShowSearchModal(true)}
>
-
+
Search for anything
@@ -377,61 +377,63 @@ export function StandardNav({ guestAllowed, alignCenter = true }) {
{!guestAllowed && (
-
+
setTerminalIsOpen(true)}
>
- Launch a machine
+ Launch a machine
router.push('/settings/billing')}
>
- Upgrade to Pro
+ Upgrade to Pro
-
- {points}
+
+ {points}
{/* Notification Bell Icon */}
-
+
{({ open }) => (
<>
-
-
+
+
-
-
- {notificationData.length > 0 ? (
- notificationData.map((notification, index) => (
-
-
-
-
{notification.message}
-
{notification.receivedTime}
-
-
- ))
- ) : (
-
No notifications
- )}
+
+
+ {notificationData.length > 0
+ ? (
+ notificationData.map((notification, index) => (
+
+
+
+
{notification.message}
+
{notification.receivedTime}
+
+
+ ))
+ )
+ : (
+
No notifications
+ )}
@@ -446,34 +448,34 @@ export function StandardNav({ guestAllowed, alignCenter = true }) {
{/*
0 */}
{/* */}
{/*
*/}
-
+
{/* Profile dropdown */}
-
+
setIsPopoverOpen(true)}
- className="flex rounded-full bg-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
+ className='flex rounded-full bg-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2'
>
- Open user menu
+ Open user menu
-
-
+
+
Profile
-
+
Settings
Feedback
Report
{role === 'ADMIN' && (
Moderation
@@ -548,8 +550,8 @@ export function StandardNav({ guestAllowed, alignCenter = true }) {
)}
>
Sign out
@@ -557,72 +559,72 @@ export function StandardNav({ guestAllowed, alignCenter = true }) {
-
+
)}
-
-
+
+
{/* Current: "bg-blue-50 border-blue-500 text-blue-700", Default: "border-transparent text-gray-300 hover:text-white" */}
Dashboard
Learn
Classes
Practice
Live
-
-
+
+
Profile
Settings
Sign out
@@ -642,19 +644,19 @@ export function StandardNav({ guestAllowed, alignCenter = true }) {
{!['/groups', '/assignments', '/submissions'].some(
(path) => router.pathname.includes(path) || !showBanner
) && (
-
-
+
+
Limited feature availability for GP. View entire site status{' '}
here
.{' '}
Dismiss
@@ -664,5 +666,5 @@ export function StandardNav({ guestAllowed, alignCenter = true }) {
>
- );
+ )
}
diff --git a/src/components/settingComponents/FreeBox.jsx b/src/components/settingComponents/FreeBox.jsx
index e23a6826..514e7acd 100644
--- a/src/components/settingComponents/FreeBox.jsx
+++ b/src/components/settingComponents/FreeBox.jsx
@@ -1,122 +1,122 @@
-export default function FreeBox() {
+export default function FreeBox () {
return (
<>
-
-
-
Standard plan
-
-
+
+
-
-
+
+
-
+
-
+
Access to challenge catalog
-
+
-
+
-
+
Limited terminal time
-
+
-
+
-
+
Limited ads
-
+
-
+
-
+
Custom banner images
-
+
-
+
-
+
PRO badge
-
+
-
+
-
+
Colored Username
-
+
-
+
-
+
Access to upcoming beta features
-
-
{' '}
>
- );
+ )
}
diff --git a/src/components/settingComponents/UpgradeBox.jsx b/src/components/settingComponents/UpgradeBox.jsx
index b4744894..a9a78cce 100644
--- a/src/components/settingComponents/UpgradeBox.jsx
+++ b/src/components/settingComponents/UpgradeBox.jsx
@@ -1,176 +1,175 @@
-import request from '@/utils/request';
-import { loadStripe } from '@stripe/stripe-js';
-const STRIPE_KEY = process.env.NEXT_PUBLIC_APP_STRIPE_KEY;
-import { useState } from 'react';
-import { motion } from 'framer-motion';
-const subscriptionTypes = ['PRO_MONTHLY', 'PRO_YEARLY'];
+import request from '@/utils/request'
+import { loadStripe } from '@stripe/stripe-js'
+import { useState } from 'react'
+import { motion } from 'framer-motion'
+const STRIPE_KEY = process.env.NEXT_PUBLIC_APP_STRIPE_KEY
+const subscriptionTypes = ['PRO_MONTHLY', 'PRO_YEARLY']
-export default function UpgradeBox() {
- const [loading, setLoading] = useState(-1);
+export default function UpgradeBox () {
+ const [loading, setLoading] = useState(-1)
const redirectToCheckout = async (subIdx) => {
- setLoading(subIdx);
+ setLoading(subIdx)
try {
-
- const stripe = await loadStripe(STRIPE_KEY);
- const subscriptionType = subscriptionTypes[subIdx];
+ const stripe = await loadStripe(STRIPE_KEY)
+ const subscriptionType = subscriptionTypes[subIdx]
const body = {
subType: subscriptionType,
quantity: 1,
operation: 'subscription',
- data: {},
+ data: {}
}
- const url = `${process.env.NEXT_PUBLIC_API_URL}/payments/stripe/create-checkout-session`;
- const session = await request(url, 'POST', body);
+ const url = `${process.env.NEXT_PUBLIC_API_URL}/payments/stripe/create-checkout-session`
+ const session = await request(url, 'POST', body)
if (session.error) {
- console.log('Creating the stripe session failed');
- return;
+ console.log('Creating the stripe session failed')
+ return
}
const result = await stripe.redirectToCheckout({
- sessionId: session.sessionId,
- });
+ sessionId: session.sessionId
+ })
if (result.error) {
- console.log(result.error.message);
+ console.log(result.error.message)
}
} catch (error) {
- console.log("INTERNAL SERVER ERRROROOROR")
- console.log(error);
+ console.log('INTERNAL SERVER ERRROROOROR')
+ console.log(error)
}
- setLoading(-1);
- };
+ setLoading(-1)
+ }
return (
<>
-
-
-
Pro plan
-
- $
-
- /month
-
-
- Yearly subscribers save $2/month
-
+
+
+
Pro plan
+
+ $
+
+ /month
+
+
+ Yearly subscribers save $2/month
+
-
-
+
+
-
+
-
+
Access to challenge catalog
-
+
-
+
-
+
Increased terminal time
-
+
-
+
-
+
No ads
-
+
-
+
-
+
Custom banner images
-
+
-
+
-
+
PRO badge
-
+
-
+
-
+
Colored username
-
+
-
+
-
+
Access to upcoming beta features
-
+
- redirectToCheckout(0)}
+ redirectToCheckout(0)}
disabled={loading !== -1}
- className="text-md bg-blue-600 flex w-full justify-center rounded-lg py-2 text-center font-medium text-white"
- whileHover={{ scale: 1.1, boxShadow: "0px 0px 8px rgb(255, 255, 255)" }}
- transition={{ type: "spring", stiffness: 100 }}
+ className='text-md bg-blue-600 flex w-full justify-center rounded-lg py-2 text-center font-medium text-white'
+ whileHover={{ scale: 1.1, boxShadow: '0px 0px 8px rgb(255, 255, 255)' }}
+ transition={{ type: 'spring', stiffness: 100 }}
>
- {loading !== -1 ? "Redirecting..." : "Subscribe"}
+ {loading !== -1 ? 'Redirecting...' : 'Subscribe'}
>
- );
-}
\ No newline at end of file
+ )
+}
diff --git a/src/pages/challenges/[...id].jsx b/src/pages/challenges/[...id].jsx
index 005c7024..bb47576f 100644
--- a/src/pages/challenges/[...id].jsx
+++ b/src/pages/challenges/[...id].jsx
@@ -1,245 +1,236 @@
-import { MarkdownViewer } from "@/components/MarkdownViewer";
-import { StandardNav } from "@/components/StandardNav";
-import request from "@/utils/request";
-import { Dialog } from "@headlessui/react";
-import { DocumentTextIcon } from "@heroicons/react/20/solid";
-import Head from "next/head";
-import Link from "next/link";
-import { useRouter } from "next/router";
-import { useEffect, useState } from "react";
-import Skeleton from "react-loading-skeleton";
-import 'react-loading-skeleton/dist/skeleton.css';
-import ReactMarkdown from "react-markdown";
-import Menu from '@/components/editor/Menu';
-import { comment } from "postcss";
-import { ToastContainer, toast } from "react-toastify";
-import 'react-toastify/dist/ReactToastify.css';
-import { getCookie } from '@/utils/request';
-import { jwtDecode } from 'jwt-decode';
-import api from '@/utils/terminal-api';
-import Confetti from 'react-confetti';
-
-
-export default function Challenge() {
- const router = useRouter();
- const [selectedWriteup, setSelectedWriteup] = useState(null);
+import { MarkdownViewer } from '@/components/MarkdownViewer'
+import { StandardNav } from '@/components/StandardNav'
+import request, { getCookie } from '@/utils/request'
+import { Dialog } from '@headlessui/react'
+import { DocumentTextIcon } from '@heroicons/react/20/solid'
+import Head from 'next/head'
+import Link from 'next/link'
+import { useRouter } from 'next/router'
+import { useEffect, useState } from 'react'
+import Skeleton from 'react-loading-skeleton'
+import 'react-loading-skeleton/dist/skeleton.css'
+import ReactMarkdown from 'react-markdown'
+import Menu from '@/components/editor/Menu'
+import { comment } from 'postcss'
+import { ToastContainer, toast } from 'react-toastify'
+import 'react-toastify/dist/ReactToastify.css'
+import { jwtDecode } from 'jwt-decode'
+import api from '@/utils/terminal-api'
+import Confetti from 'react-confetti'
+
+export default function Challenge () {
+ const router = useRouter()
+ const [selectedWriteup, setSelectedWriteup] = useState(null)
// I hate this
- const [urlChallengeId, urlSelectedTab] = (router ?? {})?.query?.id ?? [undefined, undefined];
-
+ const [urlChallengeId, urlSelectedTab] = (router ?? {})?.query?.id ?? [undefined, undefined]
// Very primitive cache system
- const [cache, _setCache] = useState({});
+ const [cache, _setCache] = useState({})
const setCache = (name, value) => {
- const newCache = { ...cache };
- newCache[name] = value;
- _setCache(newCache);
+ const newCache = { ...cache }
+ newCache[name] = value
+ _setCache(newCache)
}
// Tab system is designed to keep browser state in url,
// while mainting persistence of the terminal.
const tabs = {
- 'description': { text: 'Description', element: DescriptionPage, },
- 'write-up': { text: 'Write Up', element: WriteUpPage, },
- 'hints': { text: 'Hints', element: HintsPage, },
- 'leaderboard': { text: 'Leaderboard', element: LeaderboardPage, },
- 'comments': { text: 'Comments', element: CommentsPage, },
+ description: { text: 'Description', element: DescriptionPage },
+ 'write-up': { text: 'Write Up', element: WriteUpPage },
+ hints: { text: 'Hints', element: HintsPage },
+ leaderboard: { text: 'Leaderboard', element: LeaderboardPage },
+ comments: { text: 'Comments', element: CommentsPage }
}
- const selectedTab = tabs[urlSelectedTab] ?? tabs.description;
+ const selectedTab = tabs[urlSelectedTab] ?? tabs.description
useEffect(() => {
if (!urlChallengeId) {
- return;
+ return
}
(async () => {
if (cache.challenge) {
- return;
+ return
}
try {
- const getChallengeByIdEndPoint = `${process.env.NEXT_PUBLIC_API_URL}/challenges/${urlChallengeId}`;
- const getChallengeResult = await request(getChallengeByIdEndPoint, "GET", null);
+ const getChallengeByIdEndPoint = `${process.env.NEXT_PUBLIC_API_URL}/challenges/${urlChallengeId}`
+ const getChallengeResult = await request(getChallengeByIdEndPoint, 'GET', null)
if (getChallengeResult.success) {
- setCache("challenge", getChallengeResult.body);
+ setCache('challenge', getChallengeResult.body)
}
- } catch (error) { throw "Failed to fetch challenge: " + error; }
- })();
- }, [urlChallengeId]);
+ } catch (error) { throw 'Failed to fetch challenge: ' + error }
+ })()
+ }, [urlChallengeId])
- const [loadingFlagSubmit, setLoadingFlagSubmit] = useState(false);
- const [isPointsModalOpen, setIsPointsModalOpen] = useState(false);
- const [awardedPoints, setAwardedPoints] = useState(0);
+ const [loadingFlagSubmit, setLoadingFlagSubmit] = useState(false)
+ const [isPointsModalOpen, setIsPointsModalOpen] = useState(false)
+ const [awardedPoints, setAwardedPoints] = useState(0)
const showPointsModal = (points) => {
- setAwardedPoints(points);
- setIsPointsModalOpen(true);
- };
+ setAwardedPoints(points)
+ setIsPointsModalOpen(true)
+ }
const onSubmitFlag = (e) => {
- e.preventDefault();
+ e.preventDefault()
if (loadingFlagSubmit) {
- return;
+ return
}
- const formElements = e.target.elements;
- const flag = formElements.flag.value;
+ const formElements = e.target.elements
+ const flag = formElements.flag.value
setLoadingFlagSubmit(true);
(async () => {
try {
- const submitChallengeEndpoint = `${process.env.NEXT_PUBLIC_API_URL}/challenges/${urlChallengeId}/submissions`;
- const submitChallengeResult = await request(submitChallengeEndpoint, 'POST', { keyword: flag });
+ const submitChallengeEndpoint = `${process.env.NEXT_PUBLIC_API_URL}/challenges/${urlChallengeId}/submissions`
+ const submitChallengeResult = await request(submitChallengeEndpoint, 'POST', { keyword: flag })
console.log(submitChallengeResult)
- const { success, incorrect, error, points } = submitChallengeResult ?? {};
+ const { success, incorrect, error, points } = submitChallengeResult ?? {}
if (error || !submitChallengeResult) {
// An error occurred >:(
- toast.error(error);
- return;
+ toast.error(error)
+ return
}
if (incorrect) {
// Incorrect
- toast.error(incorrect);
- return;
+ toast.error(incorrect)
+ return
}
// Success
- showPointsModal(points); // Show points modal
+ showPointsModal(points) // Show points modal
} catch (error) {
- console.error(error);
- toast.error("An unexpected error occurred.");
+ console.error(error)
+ toast.error('An unexpected error occurred.')
} finally {
- setLoadingFlagSubmit(false);
+ setLoadingFlagSubmit(false)
}
- })();
+ })()
}
- // ========================================= STEVES TERMINAL STUFF NO TOUCHING ======================================
- const [password, setPassword] = useState("N/A");
- const [containerId, setContainerId] = useState("");
- const [userName, setUserName] = useState("");
- const [minutesRemaining, setMinutesRemaining] = useState(60);
- const [fetchingTerminal, setFetchingTerminal] = useState(true);
- const [foundTerminal, setFoundTerminal] = useState(false);
- const [terminalUrl, setTerminalUrl] = useState("");
- const [loadingMessage, setLoadingMessage] = useState('Connecting to terminal service...');
+ // ========================================= STEVES TERMINAL STUFF NO TOUCHING ======================================
+ const [password, setPassword] = useState('N/A')
+ const [containerId, setContainerId] = useState('')
+ const [userName, setUserName] = useState('')
+ const [minutesRemaining, setMinutesRemaining] = useState(60)
+ const [fetchingTerminal, setFetchingTerminal] = useState(true)
+ const [foundTerminal, setFoundTerminal] = useState(false)
+ const [terminalUrl, setTerminalUrl] = useState('')
+ const [loadingMessage, setLoadingMessage] = useState('Connecting to terminal service...')
const createTerminal = async (skipToCheckStatus) => {
- const challenge = cache.challenge;
- const cookie = getCookie('idToken');
+ const challenge = cache.challenge
+ const cookie = getCookie('idToken')
- const data = await api.buildDocketTerminal(challenge.id, cookie);
- //console.log(data)
+ const data = await api.buildDocketTerminal(challenge.id, cookie)
+ // console.log(data)
if (data) {
-
// do a quick http request to that url to see if it's up
-
+
if (!data.url) {
- toast.error("Unable to create the terminal, please try again");
- setFetchingTerminal(false);
- return;
+ toast.error('Unable to create the terminal, please try again')
+ setFetchingTerminal(false)
+ return
}
-
- setPassword(data.terminalUserPassword);
- setTerminalUrl(data.url);
- setUserName(data.terminalUserName);
- setContainerId(data.containerId);
- setFoundTerminal(true);
- setMinutesRemaining(60);
- setFetchingTerminal(false);
-
+ setPassword(data.terminalUserPassword)
+ setTerminalUrl(data.url)
+ setUserName(data.terminalUserName)
+ setContainerId(data.containerId)
+ setFoundTerminal(true)
+ setMinutesRemaining(60)
+ setFetchingTerminal(false)
} else {
- toast.error("Unable to create the terminal, please try again");
- setFetchingTerminal(false);
+ toast.error('Unable to create the terminal, please try again')
+ setFetchingTerminal(false)
}
-
- return;
- };
+ }
const checkIfTerminalExists = async () => {
- const challenge = cache.challenge;
- //console.log(challenge);
+ const challenge = cache.challenge
+ // console.log(challenge);
- const cookie = getCookie('idToken');
- if (!challenge) return;
- const data = await api.checkUserTerminal(cookie, challenge.id, 1); // 1 if using docket 2 if not
+ const cookie = getCookie('idToken')
+ if (!challenge) return
+ const data = await api.checkUserTerminal(cookie, challenge.id, 1) // 1 if using docket 2 if not
if (data !== null) {
- console.log('Found a terminal for the user');
+ console.log('Found a terminal for the user')
if (data.challengeID !== challenge.id) {
// await createTerminal(false);
} else {
- console.log('User has a terminal for this challenge');
- setTerminalUrl(data.url);
- setMinutesRemaining(data.minutesRemaining);
- setPassword(data.password);
- setUserName(data.userName);
- setFoundTerminal(true);
- setFetchingTerminal(false);
-
+ console.log('User has a terminal for this challenge')
+ setTerminalUrl(data.url)
+ setMinutesRemaining(data.minutesRemaining)
+ setPassword(data.password)
+ setUserName(data.userName)
+ setFoundTerminal(true)
+ setFetchingTerminal(false)
}
} else {
- console.log("Didnt find a terminal for the user, creating a new one");
- await createTerminal(false);
+ console.log('Didnt find a terminal for the user, creating a new one')
+ await createTerminal(false)
}
}
useEffect(() => {
if (cache.challenge) {
- checkIfTerminalExists();
+ checkIfTerminalExists()
}
}, [cache])
useEffect(() => {
const interval = setInterval(() => {
- setMinutesRemaining((prev) => (prev > 0 ? prev - 1 : 0));
- }, 60000); // 60000 ms = 1 minute
+ setMinutesRemaining((prev) => (prev > 0 ? prev - 1 : 0))
+ }, 60000) // 60000 ms = 1 minute
- return () => clearInterval(interval); // Cleanup interval on component unmount
- }, []);
+ return () => clearInterval(interval) // Cleanup interval on component unmount
+ }, [])
const copyToClipboard = (text) => {
navigator.clipboard.writeText(text).then(() => {
- toast.success("Copied to clipboard!");
+ toast.success('Copied to clipboard!')
}).catch(err => {
- toast.error("Failed to copy!");
- });
- };
-
- function formatTime(minutes) {
- const mins = Math.floor(minutes);
- const secs = Math.floor((minutes - mins) * 60);
- return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
+ toast.error('Failed to copy!')
+ })
+ }
+
+ function formatTime (minutes) {
+ const mins = Math.floor(minutes)
+ const secs = Math.floor((minutes - mins) * 60)
+ return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`
}
useEffect(() => {
- const { id } = router.query;
+ const { id } = router.query
if (id && id.length === 3 && id[1] === 'writeups') {
const writeupID = id[2];
// Fetch the writeup by ID and set it as the selected writeup
(async () => {
try {
- const response = await request(`${process.env.NEXT_PUBLIC_API_URL}/writeups/${writeupID}`, "GET", null);
+ const response = await request(`${process.env.NEXT_PUBLIC_API_URL}/writeups/${writeupID}`, 'GET', null)
if (response.success) {
- setSelectedWriteup(response.writeup);
+ setSelectedWriteup(response.writeup)
} else {
- console.error('Failed to fetch writeup:', response.message);
+ console.error('Failed to fetch writeup:', response.message)
}
} catch (error) {
- console.error('Error fetching writeup:', error);
+ console.error('Error fetching writeup:', error)
}
- })();
+ })()
}
- }, [router.query]);
+ }, [router.query])
const handleWriteupSelect = (writeup) => {
- setSelectedWriteup(writeup);
- router.push(`/challenges/${urlChallengeId}/writeups/${writeup.id}`);
- };
+ setSelectedWriteup(writeup)
+ router.push(`/challenges/${urlChallengeId}/writeups/${writeup.id}`)
+ }
return (
<>
Challenge - CTFGuide
-
-
-
-
-
-
-
- {isMobile ?
:
}
-
-
-
- Email Preferences
-
-
-
-
- Notifications
-
-
-
-
-
-
-
- Friend Requests
-
-
-
-
-
-
-
-
-
-
- Creator Notifications
-
-
- Get notified when your challenges get verified.
-
-
-
-
-
-
-
-
- Save Changes
-
-
-
+ window.removeEventListener('resize', handleResize)
+ }
+ }, [])
+
+ return (
+ <>
+
+
User Settings
+
+
+
+
+
+
+
+
+ {isMobile ?
:
}
+
+
+
+ Email Preferences
+
+
+
+
+ Notifications
+
+
+
+
+
+
+
+ Friend Requests
+
+
+
+
+
+
+
+
+
+
+ Creator Notifications
+
+
+ Get notified when your challenges get verified.
+
-
+
+
+
+
+ Save Changes
+
+
+
+
+
-
-
- >
- );
-}
\ No newline at end of file
+
+
+
+
+ >
+ )
+}
diff --git a/src/pages/settings/security.jsx b/src/pages/settings/security.jsx
index d350446d..c4a53128 100644
--- a/src/pages/settings/security.jsx
+++ b/src/pages/settings/security.jsx
@@ -1,223 +1,217 @@
-import Head from 'next/head';
-import { Footer } from '@/components/Footer';
-import { StandardNav } from '@/components/StandardNav';
-import Sidebar from '@/components/settingComponents/sidebar';
-import { useState } from 'react';
-import request from '@/utils/request';
-//const STRIPE_KEY = process.env.NEXT_PUBLIC_APP_STRIPE_KEY;
-import { Context } from '@/context';
-import { useContext, useEffect } from 'react';
-
-import { ToastContainer, toast } from 'react-toastify';
-import 'react-toastify/dist/ReactToastify.css';
-import Dropdown from '@/components/settingComponents/dropdown'; // Import the new Dropdown component
-
-
-export default function Security(){
-
- const { accountType } = useContext(Context);
- const [inputText, setInputText] = useState('');
- const [isGoogle, setIsGoogle] = useState(true);
+import Head from 'next/head'
+import { Footer } from '@/components/Footer'
+import { StandardNav } from '@/components/StandardNav'
+import Sidebar from '@/components/settingComponents/sidebar'
+import { useState, useContext, useEffect } from 'react'
+import request from '@/utils/request'
+// const STRIPE_KEY = process.env.NEXT_PUBLIC_APP_STRIPE_KEY;
+import { Context } from '@/context'
+
+import { ToastContainer, toast } from 'react-toastify'
+import 'react-toastify/dist/ReactToastify.css'
+import Dropdown from '@/components/settingComponents/dropdown' // Import the new Dropdown component
+
+export default function Security () {
+ const { accountType } = useContext(Context)
+ const [inputText, setInputText] = useState('')
+ const [isGoogle, setIsGoogle] = useState(true)
useEffect(() => {
- setIsGoogle(accountType === "GOOGLE");
- },[accountType])
+ setIsGoogle(accountType === 'GOOGLE')
+ }, [accountType])
- const user = {};
+ const user = {}
const handleInputChange = (event) => {
- setInputText(event.target.value);
- };
+ setInputText(event.target.value)
+ }
- async function saveSecurity() {
- document.getElementById('saveSecurity').innerText = 'Saving...';
- var oldPassword = document.getElementById('oldPassword').value;
- var newPassword = document.getElementById('password').value;
- var confirmPassword = document.getElementById('confirm-password').value;
+ async function saveSecurity () {
+ document.getElementById('saveSecurity').innerText = 'Saving...'
+ const oldPassword = document.getElementById('oldPassword').value
+ const newPassword = document.getElementById('password').value
+ const confirmPassword = document.getElementById('confirm-password').value
if (newPassword !== confirmPassword) {
- toast.error("Passwords do not match");
- document.getElementById('saveSecurity').innerText = 'Save';
- return;
+ toast.error('Passwords do not match')
+ document.getElementById('saveSecurity').innerText = 'Save'
+ return
}
- let valid = false;
+ let valid = false
if (newPassword.length < 8) {
- toast.error('Password must be at least 8 characters long.');
+ toast.error('Password must be at least 8 characters long.')
} else if (!/[A-Z]/.test(newPassword)) {
- toast.error('Password must contain at least one uppercase letter.');
+ toast.error('Password must contain at least one uppercase letter.')
} else if (!/[a-z]/.test(newPassword)) {
- toast.error('Password must contain at least one lowercase letter.');
+ toast.error('Password must contain at least one lowercase letter.')
} else if (!/[0-9]/.test(newPassword)) {
- toast.error('Password must contain at least one number.');
+ toast.error('Password must contain at least one number.')
} else if (!/[!@#$%^&*(),.?":{}|<>]/.test(newPassword)) {
- toast.error('Password must contain at least one special character.');
+ toast.error('Password must contain at least one special character.')
} else {
- valid = true;
+ valid = true
}
- if(!valid) {
- document.getElementById('saveSecurity').innerText = 'Save';
- return;
+ if (!valid) {
+ document.getElementById('saveSecurity').innerText = 'Save'
+ return
}
- const url = `${process.env.NEXT_PUBLIC_API_URL}/account/change-password`;
- const response = await request(url, "POST", {oldPassword, password: newPassword});
- if(!response || !response.success) {
- toast.error("Something went wrong!");
+ const url = `${process.env.NEXT_PUBLIC_API_URL}/account/change-password`
+ const response = await request(url, 'POST', { oldPassword, password: newPassword })
+ if (!response || !response.success) {
+ toast.error('Something went wrong!')
} else {
- toast.success("Your password has been updated");
+ toast.success('Your password has been updated')
+ }
+
+ try {
+ document.getElementById('saveSecurity').innerText = 'Save'
+
+ document.getElementById('password').value = ''
+ document.getElementById('confirm-password').value = ''
+ document.getElementById('oldPassword').value = ''
+ } catch (error) {
+ document.getElementById('saveSecurity').innerText = 'Save'
+ window.alert(error)
}
-
- try {
- document.getElementById('saveSecurity').innerText = 'Save';
-
- document.getElementById('password').value = '';
- document.getElementById('confirm-password').value = '';
- document.getElementById('oldPassword').value = '';
- } catch (error) {
- document.getElementById('saveSecurity').innerText = 'Save';
- window.alert(error);
}
-}
-const [isMobile, setIsMobile] = useState(false);
-
-useEffect(() => {
- const handleResize = () => {
- setIsMobile(window.innerWidth <= 768);
- };
-
- handleResize(); // Check on initial render
- window.addEventListener('resize', handleResize);
-
- return () => {
- window.removeEventListener('resize', handleResize);
- };
-}, []);
-
- return(
- <>
-
-
User Settings
-
-
-
-
-
-
-
- {isMobile ?
:
}
-
-
- Security
-
-
-
-
-
-
- Password Management
-
-
- Change your password
-
- {isGoogle && (
-
-
-
-
-
-
-
- You are using a Google Account. You will not be able to set a password for your account.
-
-
-
-
- )}
+ const [isMobile, setIsMobile] = useState(false)
-
+ useEffect(() => {
+ const handleResize = () => {
+ setIsMobile(window.innerWidth <= 768)
+ }
-
-
-
-
-
- New Password
-
-
-
+ handleResize() // Check on initial render
+ window.addEventListener('resize', handleResize)
-
-
- Confirm Password
-
-
-
+ return () => {
+ window.removeEventListener('resize', handleResize)
+ }
+ }, [])
+
+ return (
+ <>
+
+
User Settings
+
+
+
+
+
+
+
+ {isMobile ?
:
}
+
+
+ Security
+
+
+
+
+
+
+ Password Management
+
+
+ Change your password
+
+ {isGoogle && (
+
+
+
+
+
+
+ You are using a Google Account. You will not be able to set a password for your account.
+
+
-
-
- Current Password
-
-
-
-
-
-
- Save Changes
-
-
-
-
+ )}
+
+
+
+
+
+
+ New Password
+
+
+
+
+
+
+ Confirm Password
+
+
+
+
+
+
+ Current Password
+
+
+
+
+
+ Save Changes
+
+
+
+
+
-
+
+
{
pauseOnFocusLoss
draggable
pauseOnHover
- theme="dark"
+ theme='dark'
/>
-
- >
- );
+
+ >
+ )
}