diff --git a/lang/ca.json b/lang/ca.json index ee05908859..c29e58af10 100644 --- a/lang/ca.json +++ b/lang/ca.json @@ -395,6 +395,11 @@ "label.email_verify_banner": "Obté l'accés complet als teus comptes i projectes. Verifica la teva adreça de correu electrònic! ", "label.email_actions_text": "Verifica el teu correu electrònic per gestionar els teus projectes!", "label.email_error_verify": "Error de verificació del correu electrònic", + "label.email_modal_verify_your": "Verifica la teva adreça de correu electrònic", + "label.email_modal_need_verify": "Hauràs de verificar la teva adreça de correu electrònic abans de poder crear un nou projecte.", + "label.email_modal_verifying": "Verificar la teva adreça de correu electrònic assegura que puguem comunicar-nos amb tu sobre qualsevol canvi important a la plataforma. La teva adreça de correu electrònic no es compartirà públicament.", + "label.email_modal_to_verifying": "Per verificar la teva adreça de correu electrònic, edita el teu perfil i actualitza el teu correu electrònic.", + "label.email_modal_button": "Actualitza el perfil", "label.enable_change": "Habilita el canvi", "label.enable_recurring_donations": "Habilitar Donacions Recurrents", "label.ends_on": "acaba el", diff --git a/lang/en.json b/lang/en.json index 031b61d825..3edd465357 100644 --- a/lang/en.json +++ b/lang/en.json @@ -395,6 +395,14 @@ "label.email_verify_banner": "Get the full access to your accounts and projects. Verify your email address! ", "label.email_actions_text": "Verify your email to manage your projects!", "label.email_error_verify": "Error verification email", + "label.email_modal_verify_your": "Verify your email address", + "label.email_modal_need_verify": "You'll need to verify your email address before being able to create a new project.", + "label.email_modal_verifying": "Verifying your email address ensures we can communicate with you about any important changes on the platform. Your email address will not be shared publicly.", + "label.email_modal_to_verifying": "To verify your email address edit your profile and update your email.", + "label.email_modal_button": "Update profile", + + + "label.enable_change": "Enable Change", "label.enable_recurring_donations": "Enable Recurring Donations", "label.ends_on": "ends on", diff --git a/lang/es.json b/lang/es.json index 0ecd7837c8..ad2a7b3fb1 100644 --- a/lang/es.json +++ b/lang/es.json @@ -395,6 +395,11 @@ "label.email_verify_banner": "Obtén acceso completo a tus cuentas y proyectos. ¡Verifica tu dirección de correo electrónico! ", "label.email_actions_text": "¡Verifica tu correo electrónico para gestionar tus proyectos!", "label.email_error_verify": "Error de verificación del correo electrónico", + "label.email_modal_verify_your": "Verifica tu dirección de correo electrónico", + "label.email_modal_need_verify": "Necesitarás verificar tu dirección de correo electrónico antes de poder crear un nuevo proyecto.", + "label.email_modal_verifying": "Verificar tu dirección de correo electrónico asegura que podamos comunicarnos contigo sobre cualquier cambio importante en la plataforma. Tu dirección de correo electrónico no se compartirá públicamente.", + "label.email_modal_to_verifying": "Para verificar tu dirección de correo electrónico, edita tu perfil y actualiza tu correo electrónico.", + "label.email_modal_button": "Actualizar perfil", "label.enable_change": "Ayuda al Cambio", "label.enable_recurring_donations": "Habilitar Donaciones Recurrentes", "label.ends_on": "termina el", diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 2ef881021f..2e73698ce5 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -35,6 +35,7 @@ import { ETheme } from '@/features/general/general.slice'; import { setShowCompleteProfile, setShowSearchModal, + setShowVerifyEmailModal, } from '@/features/modal/modal.slice'; import { slugToProjectView } from '@/lib/routeCreators'; import { useModalCallback } from '@/hooks/useModalCallback'; @@ -138,6 +139,10 @@ const Header: FC = () => { openWalletConnectModal(); } else if (!isSignedIn) { signInThenCreate(); + } else if (!isUserRegistered(userData)) { + dispatch(setShowCompleteProfile(true)); + } else if (!userData?.isEmailVerified) { + dispatch(setShowVerifyEmailModal(true)); } else if (isUserRegistered(userData)) { router.push(Routes.CreateProject); } else { diff --git a/src/components/InputUserEmailVerify.tsx b/src/components/InputUserEmailVerify.tsx index 37244252ed..39ca986626 100644 --- a/src/components/InputUserEmailVerify.tsx +++ b/src/components/InputUserEmailVerify.tsx @@ -367,7 +367,7 @@ const InputUserEmailVerify = forwardRef( @@ -635,7 +635,7 @@ const VerifyInputButtonWrapper = styled.button` $verified ? semanticColors.jade[500] : brandColors.giv[500]}; } &:disabled { - opacity: 0.5; + opacity: ${({ $verified }) => ($verified ? '1' : '0.5')}; } `; diff --git a/src/components/controller/modal.ctrl.tsx b/src/components/controller/modal.ctrl.tsx index 84a25bc2a8..17934e8d77 100644 --- a/src/components/controller/modal.ctrl.tsx +++ b/src/components/controller/modal.ctrl.tsx @@ -4,6 +4,7 @@ import WelcomeModal from '@/components/modals/WelcomeModal'; import { FirstWelcomeModal } from '@/components/modals/FirstWelcomeModal'; import { SignWithWalletModal } from '@/components/modals/SignWithWalletModal'; import { CompleteProfileModal } from '@/components/modals/CompleteProfileModal'; +import { VerifyEmailModal } from '@/components/modals/VerifyEmailModal'; import { useIsSafeEnvironment } from '@/hooks/useSafeAutoConnect'; import { useAppDispatch, useAppSelector } from '@/features/hooks'; import { @@ -13,6 +14,7 @@ import { setShowSearchModal, setShowSwitchNetworkModal, setShowWelcomeModal, + setShowVerifyEmailModal, } from '@/features/modal/modal.slice'; import { isUserRegistered } from '@/lib/helpers'; import { SearchModal } from '../modals/SearchModal'; @@ -27,6 +29,7 @@ const ModalController = () => { showWelcomeModal, showSearchModal, showSwitchNetwork, + showVerifyEmailModal, } = useAppSelector(state => state.modal); const { userData, isSignedIn } = useAppSelector(state => state.user); @@ -103,6 +106,13 @@ const ModalController = () => { } /> )} + {showVerifyEmailModal && ( + + dispatch(setShowVerifyEmailModal(state)) + } + /> + )} ); }; diff --git a/src/components/modals/VerifyEmailModal.tsx b/src/components/modals/VerifyEmailModal.tsx new file mode 100644 index 0000000000..b9b30e95d8 --- /dev/null +++ b/src/components/modals/VerifyEmailModal.tsx @@ -0,0 +1,110 @@ +import { FC } from 'react'; +import router from 'next/router'; +import styled from 'styled-components'; +import { + brandColors, + Button, + H5, + IconProfile, + Lead, +} from '@giveth/ui-design-system'; +import { useIntl } from 'react-intl'; + +import { Modal } from '@/components/modals/Modal'; +import Routes from '@/lib/constants/Routes'; +import { IModal } from '@/types/common'; +import { useAppSelector } from '@/features/hooks'; +import { ETheme } from '@/features/general/general.slice'; +import { useModalAnimation } from '@/hooks/useModalAnimation'; + +export const VerifyEmailModal: FC = ({ setShowModal }) => { + const theme = useAppSelector(state => state.general.theme); + const { isAnimating, closeModal } = useModalAnimation(setShowModal); + const { formatMessage } = useIntl(); + + const handleClick = () => { + router.push( + { + pathname: Routes.MyAccount, + query: { opencheck: 'true' }, + }, + undefined, + { shallow: true }, + ); + closeModal(); + }; + + return ( + } + headerTitle={formatMessage({ id: 'label.complete_your_profile' })} + headerTitlePosition='left' + > + + + {formatMessage({ + id: 'label.email_modal_verify_your', + })} + +
+ {formatMessage({ + id: 'label.email_modal_need_verify', + })} +
+
+
+ {formatMessage({ + id: 'label.email_modal_verifying', + })} +
+
+
+ {formatMessage({ + id: 'label.email_modal_to_verifying', + })} +
+ + +
+
+ ); +}; + +const Container = styled(Lead)` + max-width: 528px; + padding: 24px; + text-align: left; + color: ${brandColors.deep[900]}; +`; + +const OkButton = styled(Button)` + width: 300px; + height: 48px; + margin: 48px auto 0; +`; + +const SkipButton = styled(Button)` + width: 300px; + margin: 0 auto 0; + background: transparent !important; + color: ${brandColors.pinky[500]} !important; + &:hover { + background: transparent !important; + color: ${brandColors.pinky[300]} !important; + } +`; + +const Title = styled(H5)` + margin: 24px 0; + font-weight: 700; +`; diff --git a/src/components/views/project/ProjectGIVbackToast.tsx b/src/components/views/project/ProjectGIVbackToast.tsx index 62e26d268b..d7aeda77f7 100644 --- a/src/components/views/project/ProjectGIVbackToast.tsx +++ b/src/components/views/project/ProjectGIVbackToast.tsx @@ -39,7 +39,8 @@ import { GIVBACKS_DONATION_QUALIFICATION_VALUE_USD } from '@/lib/constants/const const ProjectGIVbackToast = () => { const [showBoost, setShowBoost] = useState(false); const [showVerification, setShowVerification] = useState(false); - const { projectData, isAdmin, activateProject } = useProjectContext(); + const { projectData, isAdmin, activateProject, isAdminEmailVerified } = + useProjectContext(); const verStatus = projectData?.verificationFormStatus; const projectStatus = projectData?.status.name; const isGivbackEligible = projectData?.isGivbackEligible; @@ -74,6 +75,7 @@ const ProjectGIVbackToast = () => { const handleBoostClick = () => { if (isSSRMode) return; + if (!isAdminEmailVerified) return; if (!isEnabled) { openConnectModal?.(); } else if (!isSignedIn) { @@ -329,7 +331,7 @@ const ProjectGIVbackToast = () => { return ( <> - + {icon}
@@ -405,7 +407,7 @@ const Content = styled(Flex)` } `; -const Wrapper = styled(Flex)` +const Wrapper = styled(Flex)<{ $isverified: boolean }>` justify-content: space-between; align-items: center; gap: 24px; @@ -417,6 +419,7 @@ const Wrapper = styled(Flex)` ${mediaQueries.laptopL} { flex-direction: row; } + opacity: ${({ $isverified }) => ($isverified ? '1' : '0.75')}; `; const InnerLink = styled.a` diff --git a/src/components/views/project/ProjectIndex.tsx b/src/components/views/project/ProjectIndex.tsx index 55acb70dbc..91edab1f12 100644 --- a/src/components/views/project/ProjectIndex.tsx +++ b/src/components/views/project/ProjectIndex.tsx @@ -137,7 +137,9 @@ const ProjectIndex: FC = () => { return ( {!isAdminEmailVerified && isAdmin && } - {hasActiveQFRound && !isOnSolana && } + {hasActiveQFRound && !isOnSolana && isAdminEmailVerified && ( + + )} {title && `${title} |`} Giveth @@ -221,7 +223,11 @@ const ProjectIndex: FC = () => { {projectData && !isDraft && ( - + )} diff --git a/src/components/views/project/ProjectTabs.tsx b/src/components/views/project/ProjectTabs.tsx index 744aaf581b..9aeaf8686f 100644 --- a/src/components/views/project/ProjectTabs.tsx +++ b/src/components/views/project/ProjectTabs.tsx @@ -17,6 +17,7 @@ import { Shadow } from '@/components/styled-components/Shadow'; interface IProjectTabs { activeTab: number; slug: string; + verified?: boolean; } const badgeCount = (count?: number) => { @@ -24,7 +25,7 @@ const badgeCount = (count?: number) => { }; const ProjectTabs = (props: IProjectTabs) => { - const { activeTab, slug } = props; + const { activeTab, slug, verified } = props; const { projectData, totalDonationsCount, boostersData } = useProjectContext(); const { totalProjectUpdates } = projectData || {}; @@ -61,8 +62,22 @@ const ProjectTabs = (props: IProjectTabs) => { i.query ? `?tab=${i.query}` : '' }`} scroll={false} + onClick={e => { + if ( + !verified && + i.query === EProjectPageTabs.UPDATES + ) { + e.preventDefault(); // Prevent the link from navigating from unverified users + } + }} > - + {formatMessage({ id: i.title })} {badgeCount(i.badge) && ( ` display: flex; padding: 9px 24px; border-radius: 48px; @@ -117,6 +136,7 @@ const Tab = styled(P)` color: ${brandColors.pinky[500]}; background: ${neutralColors.gray[200]}; } + opacity: ${({ $unverified }) => ($unverified ? '0.5' : '1')}; `; const Wrapper = styled.div` diff --git a/src/components/views/userProfile/UserProfile.view.tsx b/src/components/views/userProfile/UserProfile.view.tsx index 9235c4b532..2fbd335488 100644 --- a/src/components/views/userProfile/UserProfile.view.tsx +++ b/src/components/views/userProfile/UserProfile.view.tsx @@ -47,6 +47,8 @@ import { useGeneralWallet } from '@/providers/generalWalletProvider'; export interface IUserProfileView {} const UserProfileView: FC = () => { + const router = useRouter(); + const [showModal, setShowModal] = useState(false); // follow this state to refresh user content on screen const [showUploadProfileModal, setShowUploadProfileModal] = useState(false); const [showIncompleteWarning, setShowIncompleteWarning] = useState(false); @@ -57,12 +59,16 @@ const UserProfileView: FC = () => { const [pfpData, setPfpData] = useState(); const { walletChainType, chain } = useGeneralWallet(); const { user, myAccount } = useProfileContext(); - const router = useRouter(); const pfpToken = useGiverPFPToken(user?.walletAddress, user?.avatar); const showCompleteProfile = user && !isUserRegistered(user) && showIncompleteWarning && myAccount; + // Update the modal state if the query changes + useEffect(() => { + setShowModal(!!router.query.opencheck); + }, [router.query.opencheck]); + useEffect(() => { if (user && !isUserRegistered(user) && myAccount) { setShowIncompleteWarning(true); diff --git a/src/components/views/userProfile/VerifyEmailBanner.tsx b/src/components/views/userProfile/VerifyEmailBanner.tsx index ea992647a8..0a3dfe9741 100644 --- a/src/components/views/userProfile/VerifyEmailBanner.tsx +++ b/src/components/views/userProfile/VerifyEmailBanner.tsx @@ -16,7 +16,14 @@ const VerifyEmailBanner = () => {