Compare commits

...

8 Commits

Author SHA1 Message Date
victorAnumudu 9125730d2b bug fix 2025-08-02 16:51:52 +01:00
victor.ebuka 00baa0b9bf Merge branch 'pwd-reset-started' of MERMS/MermsPanelReactJS into master 2025-08-02 15:49:02 +00:00
victorAnumudu f5018bc6b7 started password reset 2025-08-02 16:47:29 +01:00
CHIEFSOFT\ameye 59d9eb3df9 On boarding page 2025-07-30 06:34:54 -04:00
CHIEFSOFT\ameye 8f78011800 new bqckground 2025-07-29 21:41:48 -04:00
CHIEFSOFT\ameye 3c3f70fd3f Improved subscription show 2025-07-29 07:50:11 -04:00
CHIEFSOFT\ameye 4f62410e6d SUB PAGE 2025-07-28 21:56:11 -04:00
ameye b8c65ee091 Merge branch 'menu-dropdown-fix' of MERMS/MermsPanelReactJS into master 2025-07-28 22:23:31 +00:00
12 changed files with 371 additions and 65 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
.custom-bg {
background-image: url('./assets/bg/bg_1.jpg') !important;
background-image: url('./assets/bg/bg_2.jpg') !important;
background-size: cover;
background-repeat: no-repeat;
}
+4
View File
@@ -20,6 +20,8 @@ import SocketIOContextProvider from './component/context/SocketIOContext';
import CSignupPage from './views/CSignupPage';
import HelpPage from './views/HelpPage';
import SubscriptionPage from './views/SubscriptionPage';
import OnboardPage from "./views/OnboardPage";
import AccPWDResetPage from './views/AccPWDResetPage';
function AppRouters() {
@@ -34,6 +36,7 @@ function AppRouters() {
<Route path={siteLinks.signup} element={<SignupPage />} />
<Route path={siteLinks.forgetpwd} element={<ForgetpwdPage />} />
<Route path={siteLinks.csignup} element={<CSignupPage />} />
<Route path={siteLinks.accreset} element={<AccPWDResetPage />} />
<Route path={siteLinks.error} element={<LoginPage />} />
</Route>
@@ -47,6 +50,7 @@ function AppRouters() {
<Route path={siteLinks.contacts} element={<ContactsPage />} />
<Route path={siteLinks.user} element={<UserPage />} />
<Route path={siteLinks.subscription} element={<SubscriptionPage />} />
<Route path={siteLinks.onboard} element={<OnboardPage />} />
<Route path={siteLinks.calendar} element={<CalendarPage />} />
<Route path={siteLinks.settings} element={<SettingsPage />} />
<Route path={siteLinks.help} element={<HelpPage />} />
Binary file not shown.

After

Width:  |  Height:  |  Size: 390 KiB

+221
View File
@@ -0,0 +1,221 @@
import React, { useEffect, useState } from 'react'
import { Form, Formik } from "formik";
import * as Yup from "yup";
import { useDispatch } from 'react-redux'
import { Link, useNavigate, useParams } from 'react-router-dom'
import siteLinks from '../../links/siteLinks'
import { useMutation } from '@tanstack/react-query';
import { completePWDReset, verifyResetToken } from '../../services/services';
import { updateUserDetails } from '../../store/UserDetails'
import { IoMdArrowDropdown } from "react-icons/io";
import getImage from '../../utils/getImage';
const validationSchema = Yup.object().shape({
password: Yup.string().required("Password is required"),
confirmpassword: Yup.string().required("Confirm Password is required").oneOf([Yup.ref('password')], 'Passwords must match')
})
const initialValues = {
password: '',
confirmpassword: '',
};
export default function AccPWDReset() {
const {token} = useParams()
const dispatch = useDispatch()
const navigate = useNavigate()
const [user, setUser] = useState(null)
// API to verify email link
const verifyLink = useMutation({
mutationFn: (fields) => {
return verifyResetToken(fields)
},
onSuccess: (res) => {
// console.log('res', res)
if(res.data.resultCode != '0'){
throw({message: res?.data?.resultDescription})
}
// setUser({user:'testaccount', ...res.data})
setUser(res.data)
},
// onError: (err) => {
// console.log('err', err)
// }
})
const resetPWD = useMutation({
mutationFn: (fields) => {
return completePWDReset(fields)
},
onSuccess: (res) => {
if(res?.data?.resultCode != '0'){
throw({message: res?.data?.resultDescription})
}
// const {token, room, uid} = res?.data
// if(!token || !room){
// throw({message: 'something went wrong, try again!'})
// }
// localStorage.setItem('token', token)
// localStorage.setItem('room', room)
// localStorage.setItem('uid', uid)
// dispatch(updateUserDetails({ ...res?.data }));
// navigate('/dash') // later add redux to dispatch state
},
// onError: (err) => {
// console.log('err', err)
// }
})
const handleCompletePWDReset = (values) => {
let reqData = {
reset_token: token,
// reset_uid: "4733e96b-7031-4684-bec3-f63da4417707",
reset_uid: "",
new_password: values.password,
}
resetPWD.mutate(reqData)
}
useEffect(()=>{
if(!token){
return navigate(siteLinks.login, {replace: true})
}
verifyLink.mutate({reset_token: token})
}, [])
return (
<div className="app">
<div className="app-wrap">
<div className="app-contant">
<div className="vh-100 bg-white custom-bg">
<div className="container-fluid p-0">
<div className="row no-gutters justify-content-center">
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1" style={{maxWidth: '520px'}}>
<div className="mt-5 d-flex">
<div className="bg-white register p-5">
<h1 className="mb-2">MERMS Panel</h1>
{(verifyLink.isSuccess && !resetPWD.isSuccess) && <p>Complete your password reset</p>}
<div
>
<div className='mt-2'>
<div className="row">
{resetPWD.isSuccess ?
<>
<div className='col-12'>
<div className="rounded-2 d-flex flex-column justify-content-between align-items-center" style={{backgroundColor: '#F2FAF7'}}>
<h4 className='p-4 text-black'>Your password reset is completed</h4>
<img className='' style={{width: '150px'}} src={getImage('reset-password.png')} alt='reset-icon' />
<Link to={siteLinks.login} className='p-2 text-primary' style={{color: '#6FCAEF'}}>Home</Link>
</div>
</div>
<div className="col-12 mt-3">
<p>Go <Link to={siteLinks.home}> Back</Link></p>
</div>
</>
:
<>
{verifyLink.isPending ?
<div className='col-12'>
<div className="rounded-2 d-flex flex-column justify-content-center align-items-center" style={{height: '200px', backgroundColor: '#F2FAF7'}}>
<div className="col-12 d-flex flex-column justify-content-center align-items-center">
<p className='text-black'>loading...</p>
</div>
</div>
</div>
: verifyLink.isSuccess ?
<div className='col-12'>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleCompletePWDReset}
>
{(props) => {
return (
<Form className='mt-2'>
<div className="row">
<>
<div className="col-12">
<div className="form-group">
<label className={`text-black fw-bold control-label`}>Username: {user?.user}</label>
</div>
</div>
<div className="col-12">
<div className="form-group">
<label className={`text-black fw-bold control-label ${(props.errors.password && props.touched.password) && 'text-danger'}`}>Password*</label>
<input type="password" name='password' className="form-control" placeholder="password" value={props.values.password} onChange={props.handleChange} />
</div>
</div>
<div className="col-12">
<div className="form-group">
<label className={`text-black fw-bold control-label`}>Confirm Password* <span className={`${(props.errors.confirmpassword && props.touched.confirmpassword) && 'text-danger'}`}>{(props.errors.confirmpassword && props.touched.confirmpassword) && props.errors.confirmpassword}</span></label>
<input type="password" name='confirmpassword' className="form-control" placeholder="confirmpassword" value={props.values.confirmpassword} onChange={props.handleChange} />
</div>
</div>
{resetPWD.error &&
<>
<div className="col-12">
<p className='text-danger'>{resetPWD.error.message}</p>
</div>
</>
}
<div className="col-12 mt-3 text-end">
<button type='submit' className="btn btn-primary text-uppercase">{resetPWD.isPending ? 'loading...' : 'reset password'}</button>
</div>
</>
</div>
</Form>
);
}}
</Formik>
</div>
: verifyLink.error ?
<>
<div className='col-12'>
<div className="rounded-2 d-flex flex-column justify-content-between align-items-center" style={{backgroundColor: '#E9D0DD'}}>
<h4 className='p-4 text-black'>Unable to continue password reset. Please start again</h4>
<img className='' style={{width: '150px'}} src={getImage('reset-password.png')} alt='reset-icon' />
<Link to={siteLinks.login} className='p-2 text-primary' style={{color: '#6FCAEF'}}>Home</Link>
</div>
</div>
<div className="col-12 mt-3">
<p>Go <Link to={siteLinks.home}> Back</Link></p>
</div>
</>
:
null
}
</>
}
</div>
</div>
</div>
</div>
</div>
</div>
{/* <div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="row align-items-center h-100">
<div className="col-7 mx-auto ">
<img className="img-fluid" src={LoginImg} alt="" />
</div>
</div>
</div> */}
</div>
</div>
</div>
</div>
</div>
</div>
)
}
@@ -90,8 +90,8 @@ export default function UserHeader(){
</div>
</div>
<div className="p-4">
<Link className="dropdown-item d-flex nav-link" to={siteLinks.user}>
<i className="fa fa-user pr-2 text-success"></i> Users</Link>
<Link className="dropdown-item d-flex nav-link" to={siteLinks.subscription}>
<i className="fa fa-user pr-2 text-success"></i> Subscription</Link>
<Link className="dropdown-item d-flex nav-link" to={siteLinks.contacts}>
<i className="fa fa-envelope pr-2 text-primary"></i> Contacts
<span className="badge badge-primary ml-auto">6</span>
+1 -1
View File
@@ -48,7 +48,7 @@ export default function UserMenu() {
</div>
</Link>
<ul id="collapseTwo" className="collapse" aria-labelledby="headingTwo" data-bs-parent="#sidebarNav">
<li className={`${pathname == siteLinks.user ? 'active' : ''}`}><Link to={siteLinks.user}>Users</Link></li>
<li className={`${pathname == siteLinks.subscription ? 'active' : ''}`}><Link to={siteLinks.subscription}>Subscription</Link></li>
<li className={`${pathname == siteLinks.settings ? 'active' : ''}`}><Link to={siteLinks.settings}>Settings</Link></li>
</ul>
</li>
+71
View File
@@ -0,0 +1,71 @@
import React from 'react'
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import getImage from "../../utils/getImage";
export default function Onboard() {
const pricingFields ={
starter: { name: 'Starter', price: 5.99, active: true },
basic: { name: 'Basic', price: 12.99, active: true },
premium: { name: 'Premium', price: 20.00, active: true },
}
return (
<>
<BreadcrumbComBS title='Subscription' paths={['Dashboard', 'Subscription']} />
<div className="row">
<div className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>Current Subscription(s)</h5>
<h2 className="text-primary pt-3">Basic</h2>
{/*<p className="text-primary pb-3">/ Monthly</p>*/}
{/*<ul className="py-2">*/}
{/* <li>post jobs</li>*/}
{/* <li>advanced instructors search</li>*/}
{/* <li>invite candidates</li>*/}
{/* <li>post events</li>*/}
{/* <li>cancel any time</li>*/}
{/*</ul>*/}
</div>
</div>
</div>
</div>
<>
{Object.entries(pricingFields)?.map(([key, value]) => (
<div key={key} className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>{value.name}</h5>
<h2 className="text-primary pt-3">${value.price}</h2>
<p className="text-primary pb-3">/ Monthly</p>
<ul className="py-2">
<li>post jobs</li>
<li>advanced instructors search</li>
<li>invite candidates</li>
<li>post events</li>
<li>cancel any time</li>
</ul>
<div className="pt-2"><a href="javascript:void(0)" className="btn btn-inverse-secondary btn-round btn-sm">go {value.name}</a></div>
</div>
</div>
</div>
</div>
))}
</>
</div>
</>
)
}
+40 -58
View File
@@ -1,10 +1,18 @@
import React from 'react'
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import getImage from "../../utils/getImage";
export default function Subscription() {
const pricingFields ={
starter: { name: 'Starter', price: 5.99, active: true },
basic: { name: 'Basic', price: 12.99, active: true },
premium: { name: 'Premium', price: 20.00, active: true },
}
return (
<>
<BreadcrumbComBS title='Home' paths={['Dashboard', 'Subscription']} />
<BreadcrumbComBS title='Subscription' paths={['Dashboard', 'Subscription']} />
@@ -13,7 +21,16 @@ export default function Subscription() {
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>Current Subscription(s)</h5>
<h2 className="text-primary pt-3">Basic</h2>
{/*<p className="text-primary pb-3">/ Monthly</p>*/}
{/*<ul className="py-2">*/}
{/* <li>post jobs</li>*/}
{/* <li>advanced instructors search</li>*/}
{/* <li>invite candidates</li>*/}
{/* <li>post events</li>*/}
{/* <li>cancel any time</li>*/}
{/*</ul>*/}
</div>
@@ -21,66 +38,31 @@ export default function Subscription() {
</div>
</div>
<div className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>Premium</h5>
<h2 className="text-primary pt-3">$150</h2>
<p className="text-primary pb-3">/ Monthly</p>
<ul className="py-2">
<li>post jobs</li>
<li>advanced instructors search</li>
<li>invite candidates</li>
<li>post events</li>
<li>cancel any time</li>
</ul>
<div className="pt-2"><a href="javascript:void(0)" className="btn btn-primary btn-round btn-sm">go premium</a></div>
<>
{Object.entries(pricingFields)?.map(([key, value]) => (
<div key={key} className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>{value.name}</h5>
<h2 className="text-primary pt-3">${value.price}</h2>
<p className="text-primary pb-3">/ Monthly</p>
<ul className="py-2">
<li>post jobs</li>
<li>advanced instructors search</li>
<li>invite candidates</li>
<li>post events</li>
<li>cancel any time</li>
</ul>
<div className="pt-2"><a href="javascript:void(0)" className="btn btn-inverse-secondary btn-round btn-sm">go {value.name}</a></div>
</div>
</div>
</div>
</div>
</div>
<div className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>basic</h5>
<h2 className="text-primary pt-3">$130</h2>
<p className="text-primary pb-3">/ Monthly</p>
<ul className="py-2">
<li>post jobs</li>
<li>advanced instructors search</li>
<li>invite candidates</li>
<li>post events</li>
<li>cancel any time</li>
</ul>
<div className="pt-2"><a href="javascript:void(0)" className="btn btn-inverse-secondary btn-round btn-sm">go premium</a></div>
</div>
</div>
</div>
</div>
<div className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>starter</h5>
<h2 className="text-primary pt-3">$100</h2>
<p className="text-primary pb-3">/ Monthly</p>
<ul className="py-2">
<li>post jobs</li>
<li>advanced instructors search</li>
<li>invite candidates</li>
<li>post events</li>
<li>cancel any time</li>
</ul>
<div className="pt-2"><a href="javascript:void(0)" className="btn btn-inverse-secondary btn-round btn-sm">go premium</a></div>
</div>
</div>
</div>
</div>
))}
</>
</div>
+3 -1
View File
@@ -8,13 +8,15 @@ const siteLinks = {
comments: '/comments',
reports: '/reports',
subscription: '/subscription',
onboard: '/subscription',
user: '/user',
calendar: '/calendar',
settings: '/settings',
login: '/auth/login',
signup: '/auth/signup',
forgetpwd: '/auth/forgetpwd',
csignup: '/csignup/:jwt'
csignup: '/csignup/:jwt',
accreset: '/accreset/:token'
}
export default siteLinks
+14 -2
View File
@@ -134,9 +134,21 @@ export const recentActions = (reqData) => {
return postAuxEnd(`/panel/account/actions`, postData, false)
}
// FUNCTION TO VERIFY RESET TOKEN
export const verifyResetToken = (reqData) => {
let postData = {
...reqData
}
return postAuxEnd('/panel/auth/resetverify', postData, false)
}
// FUNCTION TO COMPLETE PASSWORD RESET
export const completePWDReset = (reqData) => {
let postData = {
...reqData
}
return postAuxEnd('/panel/auth/resetcomplete', postData, false)
}
+7
View File
@@ -0,0 +1,7 @@
import AccPWDReset from '../component/auth/AccPWDReset'
export default function AccPWDResetPage() {
return (
<AccPWDReset />
)
}
+7
View File
@@ -0,0 +1,7 @@
import Onboard from '../component/onboard/Onboard';
export default function OnboardPage(){
return <Onboard />
}