diff --git a/src/components/settingComponents/FreeBox.jsx b/src/components/settingComponents/FreeBox.jsx index 480a47e1..569d5a00 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
-
- +
+
+
Standard plan
+
+ Free
-
    -
  • +
      +
    • - + Acess to challenge catalog
    • -
    • +
    • - + Limited terminal time
    • -
    • +
    • - + Limited ads
    • -
    • +
    • - + Custom banner images
    • -
    • +
    • - + PRO badge
    • -
    • +
    • - + Colored Username
    • -
    • +
    • - + Acess to upcoming beta features
    -
    -
    +
    +
    Current plan
    {' '} - ); + ) } diff --git a/src/components/settingComponents/UpgradeBox.jsx b/src/components/settingComponents/UpgradeBox.jsx index 52ab6552..1f7dcd29 100644 --- a/src/components/settingComponents/UpgradeBox.jsx +++ b/src/components/settingComponents/UpgradeBox.jsx @@ -1,125 +1,125 @@ -export default function UpgradeBox() { +export default function UpgradeBox () { return ( <> -
    -
    -
    Pro plan
    -
    - $ - 5 - /month +
    +
    +
    Pro plan
    +
    + $ + 5 + /month
    -
    +
    Yearly subscribers save $2/month
    -
      -
    • +
        +
      • - + Acess to challenge catalog
      • -
      • +
      • - + Increased terminal time
      • -
      • +
      • - + No ads
      • -
      • +
      • - + Custom banner images
      • -
      • +
      • - + PRO badge
      • -
      • +
      • - + Colored username
      • -
      • +
      • - + Acess to upcoming beta features
      -
      -
    - ); + ) } diff --git a/src/pages/login.jsx b/src/pages/login.jsx index d09a73e9..56588aee 100644 --- a/src/pages/login.jsx +++ b/src/pages/login.jsx @@ -1,95 +1,94 @@ -import Head from 'next/head'; -import Link from 'next/link'; -import { useState } from 'react'; -import router from 'next/router'; +import Head from 'next/head' +import Link from 'next/link' +import { useState, useContext } from 'react' +import router from 'next/router' -import { OnboardingFlow } from '@/components/onboarding/OnboardingFlow'; -import { ToastContainer, toast } from 'react-toastify'; -import 'react-toastify/dist/ReactToastify.css'; -import AuthFooter from '@/components/auth/AuthFooter'; -import { GoogleLogin } from '@react-oauth/google'; -import { jwtDecode } from 'jwt-decode'; +import { OnboardingFlow } from '@/components/onboarding/OnboardingFlow' +import { ToastContainer, toast } from 'react-toastify' +import 'react-toastify/dist/ReactToastify.css' +import AuthFooter from '@/components/auth/AuthFooter' +import { GoogleLogin } from '@react-oauth/google' +import { jwtDecode } from 'jwt-decode' -import { Context } from '@/context'; -import { useContext } from 'react'; +import { Context } from '@/context' -export default function Login() { - const state = useContext(Context); +export default function Login () { + const state = useContext(Context) - const [isLoading, setIsLoading] = useState(false); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [accountType, setAccountType] = useState('EMAIL'); // ['EMAIL', 'GOOGLE'] - const [showOnboarding, setShowOnboarding] = useState(false); + const [isLoading, setIsLoading] = useState(false) + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [accountType, setAccountType] = useState('EMAIL') // ['EMAIL', 'GOOGLE'] + const [showOnboarding, setShowOnboarding] = useState(false) + + async function handleLoginRequest (requestOptions, isGoogle) { + setIsLoading(true) - async function handleLoginRequest(requestOptions, isGoogle) { - setIsLoading(true); - try { - const url = process.env.NEXT_PUBLIC_API_URL + '/account/login'; - const response = await fetch(url, requestOptions); - if(response.status === 404) { - if(isGoogle) { - setShowOnboarding(true); - return; + const url = process.env.NEXT_PUBLIC_API_URL + '/account/login' + const response = await fetch(url, requestOptions) + if (response.status === 404) { + if (isGoogle) { + setShowOnboarding(true) + return } } - let data = await response.json(); - let { success, token, body } = data; + const data = await response.json() + const { success, token, body } = data if (success) { - document.cookie = `idToken=${token}; SameSite=None; Secure; Path=/`; + document.cookie = `idToken=${token}; SameSite=None; Secure; Path=/` - localStorage.setItem('username', body.username); - localStorage.setItem('firstname', body.firstName); - localStorage.setItem('lastname', body.lastName); - localStorage.setItem('birthday', body.birthday); + localStorage.setItem('username', body.username) + localStorage.setItem('firstname', body.firstName) + localStorage.setItem('lastname', body.lastName) + localStorage.setItem('birthday', body.birthday) - state.setRole(body.role); - state.setUsername(body.username); - state.setProfilePic(body.profileImage); - state.setAccountType(body.accountType); + state.setRole(body.role) + state.setUsername(body.username) + state.setProfilePic(body.profileImage) + state.setAccountType(body.accountType) - router.push('/dashboard'); + router.push('/dashboard') } else { - toast.error(data.message); + toast.error(data.message) } - } catch(error) { - console.log(error); + } catch (error) { + console.log(error) } - setIsLoading(false); + setIsLoading(false) } const handleLogin = async (e) => { - e.preventDefault(); - const requestOptions = { - method: 'POST', - body: JSON.stringify({ email, password, accountType: 'EMAIL'}), - headers: { 'Content-Type': 'application/json' } - }; - setAccountType('EMAIL'); - await handleLoginRequest(requestOptions, false); + e.preventDefault() + const requestOptions = { + method: 'POST', + body: JSON.stringify({ email, password, accountType: 'EMAIL' }), + headers: { 'Content-Type': 'application/json' } + } + setAccountType('EMAIL') + await handleLoginRequest(requestOptions, false) } - async function handleSuccess(data) { - const { credential } = data; - const decode = jwtDecode(credential); - const { email } = decode; - setEmail(email); - const requestOptions = { - method: 'POST', - body: JSON.stringify({ email, password: null, accountType: 'GOOGLE'}), + async function handleSuccess (data) { + const { credential } = data + const decode = jwtDecode(credential) + const { email } = decode + setEmail(email) + const requestOptions = { + method: 'POST', + body: JSON.stringify({ email, password: null, accountType: 'GOOGLE' }), headers: { 'Content-Type': 'application/json' } - }; - setAccountType('GOOGLE'); - await handleLoginRequest(requestOptions, true); + } + setAccountType('GOOGLE') + await handleLoginRequest(requestOptions, true) } - async function handleError(data) { - console.log(data); - toast.error('Google login failed. Please try again later.'); + async function handleError (data) { + console.log(data) + toast.error('Google login failed. Please try again later.') } - if(showOnboarding) return + if (showOnboarding) return return ( <> @@ -104,37 +103,36 @@ export default function Login() { backgroundPosition: 'center', backgroundRepeat: 'repeat', width: '100%', - height: '100%', - }}> + height: '100%' + }} + >
    -

    You are on the preview version of CTFGuide. Preview accounts do not use the same authentication system as https://ctfguide.com

    -

    Account data may not persist. Features may not work as expected.

    -

    You assume all risk by using preview.ctfguide.com.

    +

    You are on the preview version of CTFGuide. Preview accounts do not use the same authentication system as https://ctfguide.com

    +

    Account data may not persist. Features may not work as expected.

    +

    You assume all risk by using preview.ctfguide.com.

    + + Take me to the main site -Take me to the main site -
    -
    +
    -
    - -
    +
    -
    +
    -

    +

    Something went wrong.

    @@ -142,69 +140,69 @@ export default function Login() {

    Login to

    - + CTFGuide -

    CTFGuide

    +

    CTFGuide

    -

    +

    router.push('/register')} - className="font-semibold text-blue-600 hover:text-blue-700 cursor-pointer" + className='font-semibold text-blue-600 hover:text-blue-700 cursor-pointer' > Don't have an account?

    -
    +
    setEmail(e.target.value)} - type="text" - autoComplete="email" + type='text' + autoComplete='email' required - className="block w-full appearance-none rounded-sm border border-gray-300 px-3 py-2 text-white placeholder-gray-400 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 sm:text-sm" + className='block w-full appearance-none rounded-sm border border-gray-300 px-3 py-2 text-white placeholder-gray-400 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 sm:text-sm' />
    -
    +
    setPassword(e.target.value)} - type="password" - autoComplete="current-password" + type='password' + autoComplete='current-password' required - className="block w-full appearance-none rounded-sm border border-gray-300 px-3 py-2 text-white placeholder-gray-400 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 sm:text-sm" + className='block w-full appearance-none rounded-sm border border-gray-300 px-3 py-2 text-white placeholder-gray-400 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 sm:text-sm' />
    -
    -
    +
    +
    Forgot your password? @@ -213,54 +211,54 @@ export default function Login() {
    -
    -
    +
    +
    handleSuccess(data)} onFailure={(data) => handleError(data)} - text="continue_with" // Custom button text - theme="filled_black" // Optional: Choose between "default", "dark", or "light" themes - width="370" // Optional: Custom button width + text='continue_with' // Custom button text + theme='filled_black' // Optional: Choose between "default", "dark", or "light" themes + width='370' // Optional: Custom button width />
    -
    - - +
    @@ -269,7 +267,7 @@ export default function Login() {
    - ); + ) } -function OnBoardingTransition(props) { +function OnBoardingTransition (props) { console.log('OnboardingTransition') - console.log(props); - const { email, password, accountType } = props; + console.log(props) + const { email, password, accountType } = props return ( <> Dashboard - CTFGuide
    -
    +
    ) -} \ No newline at end of file +} diff --git a/src/pages/settings/billing.jsx b/src/pages/settings/billing.jsx index e8ae327b..2c03bed1 100644 --- a/src/pages/settings/billing.jsx +++ b/src/pages/settings/billing.jsx @@ -1,21 +1,21 @@ -import { loadStripe } from '@stripe/stripe-js'; -const STRIPE_KEY = process.env.NEXT_PUBLIC_APP_STRIPE_KEY; -import Head from 'next/head'; -import { Footer } from '@/components/Footer'; -import { useState, useEffect } from 'react'; - -import { StandardNav } from '@/components/StandardNav'; -import Sidebar from '@/components/settingComponents/sidebar'; -import UpgradeBox from '@/components/settingComponents/UpgradeBox'; -import FreeBox from '@/components/settingComponents/FreeBox'; -import Dropdown from '@/components/settingComponents/dropdown'; // Import the new Dropdown component - -export default function Billing() { +import { loadStripe } from '@stripe/stripe-js' +import Head from 'next/head' +import { Footer } from '@/components/Footer' +import { useState, useEffect } from 'react' + +import { StandardNav } from '@/components/StandardNav' +import Sidebar from '@/components/settingComponents/sidebar' +import UpgradeBox from '@/components/settingComponents/UpgradeBox' +import FreeBox from '@/components/settingComponents/FreeBox' +import Dropdown from '@/components/settingComponents/dropdown' +const STRIPE_KEY = process.env.NEXT_PUBLIC_APP_STRIPE_KEY // Import the new Dropdown component + +export default function Billing () { const redirectToCheckout = async (event) => { try { - const stripe = await loadStripe(STRIPE_KEY); - const subscriptionType = document.getElementById('paymentType').value; - // console.log(subscriptionType); + const stripe = await loadStripe(STRIPE_KEY) + const subscriptionType = document.getElementById('paymentType').value + // console.log(subscriptionType); const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/payments/stripe/create-checkout-session`, @@ -25,37 +25,37 @@ export default function Billing() { subType: subscriptionType, quantity: 1, operation: 'subscription', - data: {}, + data: {} }), headers: { - 'Content-Type': 'application/json', + 'Content-Type': 'application/json' }, - credentials: 'include', + credentials: 'include' } - ); + ) - const session = await response.json(); + const session = await response.json() 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); } } catch (error) { - console.log(error); + console.log(error) } - }; + } const updateCardInfo = async () => { try { - const stripe = await loadStripe(STRIPE_KEY); - const subscriptionType = document.getElementById('paymentType').value; + const stripe = await loadStripe(STRIPE_KEY) + const subscriptionType = document.getElementById('paymentType').value const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/payments/stripe/update-card`, @@ -63,67 +63,67 @@ export default function Billing() { method: 'POST', credentials: 'include', body: JSON.stringify({ - subType: subscriptionType, + subType: subscriptionType }), headers: { - 'Content-Type': 'application/json', - }, + 'Content-Type': 'application/json' + } } - ); + ) - const session = await response.json(); + const session = await response.json() await stripe.redirectToCheckout({ - sessionId: session.sessionId, - }); + sessionId: session.sessionId + }) } catch (error) { - console.log(error); + console.log(error) } - }; + } const cancelSubscription = async () => { try { - const subscriptionType = document.getElementById('paymentType').value; - const url = `${process.env.NEXT_PUBLIC_API_URL}/payments/stripe/cancel`; + const subscriptionType = document.getElementById('paymentType').value + const url = `${process.env.NEXT_PUBLIC_API_URL}/payments/stripe/cancel` const response = await fetch(url, { method: 'PUT', credentials: 'include', body: JSON.stringify({ - subType: subscriptionType, + subType: subscriptionType }), headers: { - 'Content-Type': 'application/json', - }, - }); - const data = await response.json(); - // console.log(data.message); + 'Content-Type': 'application/json' + } + }) + const data = await response.json() + // console.log(data.message); } catch (err) { - console.log(err); + console.log(err) } - }; + } - const [isMobile, setIsMobile] = useState(false); + const [isMobile, setIsMobile] = useState(false) useEffect(() => { const handleResize = () => { - setIsMobile(window.innerWidth <= 768); - }; + setIsMobile(window.innerWidth <= 768) + } - handleResize(); // Check on initial render - window.addEventListener('resize', handleResize); + handleResize() // Check on initial render + window.addEventListener('resize', handleResize) return () => { - window.removeEventListener('resize', handleResize); - }; - }, []); + window.removeEventListener('resize', handleResize) + } + }, []) return ( <> User Settings