diff --git a/client/i18n/locales/english/translations.json b/client/i18n/locales/english/translations.json index b63f93bd518..13b15f63e76 100644 --- a/client/i18n/locales/english/translations.json +++ b/client/i18n/locales/english/translations.json @@ -927,5 +927,12 @@ "p2": "This action will sign you out of your account on this device and browser session only. Please confirm if you would like to proceed.", "certain": "Yes, sign out of my account", "nevermind": "Nevermind, I don't want to sign out" + }, + "staging-warning": { + "heading": "Warning: This is an Early Access - Test Deployment", + "p1": "We welcome you to test this release in a test-only mode and get early access to upcoming platform features. Sometimes these changes are referred to as next, beta, staging, etc. interchangeably.", + "p2": "We thank you for reporting bugs that you encounter and help in making freeCodeCamp.org better.", + "p3": "Your progress MAY NOT be saved on your next visit, and any certifications claimed on this deployment are not valid. Learn more by <0>following this link.", + "certain": "Accept and Dismiss" } } diff --git a/client/src/components/layouts/default.tsx b/client/src/components/layouts/default.tsx index da2e7f66188..661a7ed8f39 100644 --- a/client/src/components/layouts/default.tsx +++ b/client/src/components/layouts/default.tsx @@ -40,10 +40,12 @@ import BreadCrumb from '../../templates/Challenges/components/bread-crumb'; import Flash from '../Flash'; import { flashMessageSelector, removeFlashMessage } from '../Flash/redux'; import SignoutModal from '../signout-modal'; +import StagingWarningModal from '../staging-warning-modal'; import Footer from '../Footer'; import Header from '../Header'; import OfflineWarning from '../OfflineWarning'; import { Loader } from '../helpers'; +import envData from '../../../../config/env.json'; // preload common fonts import './fonts.css'; @@ -169,6 +171,8 @@ function DefaultLayout({ } else { return (
+ {envData.deploymentEnv === 'staging' && + envData.environment === 'production' && } { + setShow(false); + }; + const handleClick = () => { + store.set('acceptedStagingWarning', true); + setShow(false); + }; + return ( + + + + + {t('staging-warning.heading')} + + + + +

{t('staging-warning.p1')}

+

{t('staging-warning.p2')}

+

+ + + link + + +

+
+ + +
+
+ ); +} + +export default StagingWarningModal; diff --git a/client/src/components/staging-warning-modal/staging-warning-modal.test.tsx b/client/src/components/staging-warning-modal/staging-warning-modal.test.tsx new file mode 100644 index 00000000000..8c816e7e9d8 --- /dev/null +++ b/client/src/components/staging-warning-modal/staging-warning-modal.test.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import store from 'store'; +import StagingWarningModal from '.'; + +describe('StagingWarningModal', () => { + it('renders the modal successfully', () => { + render(); + expect(screen.getByTestId('staging-warning-modal')).toBeInTheDocument(); + expect(screen.getByTestId('staging-warning-modal')).toHaveClass('in'); + }); + + it('closes the modal when clicking the close button', () => { + render(); + fireEvent.click(screen.getByText('Close')); + expect(screen.getByTestId('staging-warning-modal')).not.toHaveClass('in'); + }); + + it('displays the correct modal content', () => { + render(); + const modalContent = screen.getByTestId('staging-warning-modal'); + expect(modalContent).toHaveTextContent('staging-warning.heading'); + expect(modalContent).toHaveTextContent('staging-warning.p1'); + expect(modalContent).toHaveTextContent('staging-warning.p2'); + expect(modalContent).toHaveTextContent('link'); + }); + + it('accepts Warning, stores acceptance key in local storage, and closes the modal', () => { + render(); + fireEvent.click(screen.getByTestId('accepts-warning')); + expect(store.get('acceptedStagingWarning')).toBe(true); + expect(screen.queryByTestId('staging-warning-modal')).not.toHaveClass('in'); + }); +});