Compare commits

..

26 Commits

Author SHA1 Message Date
ameye 47d3bded9d style changes 2026-05-23 10:08:05 -04:00
ameye 22c7182993 StripeSubscriptionButton 2026-05-23 09:15:37 -04:00
CHIEFSOFT\ameye 29a2c937fe removed Subscription 2026-05-23 08:35:50 -04:00
CHIEFSOFT\ameye 3a81da3713 removed Subscription 2026-05-23 08:24:59 -04:00
ameye 4ace1acda3 inform before charges 2026-05-23 08:20:18 -04:00
CHIEFSOFT\ameye 04afae48a2 removed Subscription 2026-05-23 07:48:18 -04:00
CHIEFSOFT\ameye 1a35a8c9b8 removed Subscription 2026-05-23 07:37:31 -04:00
ameye 4f3fb44fcd Merge branch 'bug-fix' of MERMS/MermsPanelReactJS into master 2026-05-20 20:02:01 +00:00
victorAnumudu ef24f269dc refresh provisioning bug fixed 2026-05-20 18:14:00 +01:00
ameye 51df8293c3 Merge branch 'socket-provision-refresh' of MERMS/MermsPanelReactJS into master 2026-05-19 21:52:35 +00:00
victorAnumudu 546b6177dc made product page to reload on when provision is done 2026-05-19 18:20:10 +01:00
ameye db116f36e3 Merge branch 'img-list-width-adjust' of MERMS/MermsPanelReactJS into master 2026-05-18 17:27:24 +00:00
victorAnumudu 4f93c5b2c2 img list width adjusted 2026-05-18 18:25:49 +01:00
ameye 0a3ca0234e Merge branch 'captcha-centering' of MERMS/MermsPanelReactJS into master 2026-05-18 17:05:50 +00:00
victorAnumudu a88da5cf0e centralized captcha section 2026-05-18 17:12:00 +01:00
CHIEFSOFT\ameye 159f1fcdc8 Added report starter 2026-05-16 17:31:48 -04:00
CHIEFSOFT\ameye f50df99417 Email is required 2026-05-16 04:53:23 -04:00
CHIEFSOFT\ameye 9217e88831 Turnstile 2026-05-16 04:26:50 -04:00
CHIEFSOFT\ameye 49c6c6afe9 turnstile 2026-05-16 03:59:39 -04:00
CHIEFSOFT\ameye ffd00155e0 REACT_APP_TURNSTILE_SITE_KEY 2026-05-16 03:23:36 -04:00
CHIEFSOFT\ameye 9fd3636ffd NEXT_SITE_SECURITY_KEY 2026-05-16 03:14:41 -04:00
CHIEFSOFT\ameye 5ff6b4a4d2 NEXT_SITE_SECURITY_KEY 2026-05-16 03:08:05 -04:00
CHIEFSOFT\ameye 22c431c8e0 Turnstile 2026-05-16 02:47:51 -04:00
ameye 2db3a4d6f4 Merge branch 'picture-payload-removal' of MERMS/MermsPanelReactJS into master 2026-05-14 17:11:06 +00:00
victorAnumudu 1310561e55 removed picture payload from the update profile endpoint 2026-05-14 18:00:04 +01:00
ameye edcb6cac7d Merge branch 'login-bug-fix' of MERMS/MermsPanelReactJS into master 2026-05-11 17:13:11 +00:00
22 changed files with 12105 additions and 5990 deletions
+4
View File
@@ -23,3 +23,7 @@ REACT_APP_DNS1='dns1.mermsemr.net'
REACT_APP_DNS2='dns1.mermsemr.net'
REACT_APP_DNS_LINK='https://qa-www.mermsemr.com/info/dns'
#CLOUDFLARE
REACT_APP_TURNSTILE_SITE_KEY=0x4AAAAAADQV82wuocFR-u5O
+3
View File
@@ -24,3 +24,6 @@ REACT_APP_DNS1='dns1.mermsemr.net'
REACT_APP_DNS2='dns1.mermsemr.net'
REACT_APP_DNS_LINK='https://qa-www.mermsemr.com/info/dns'
#CLOUDFLARE
REACT_APP_TURNSTILE_SITE_KEY=0x4AAAAAADQV82wuocFR-u5O
+5 -1
View File
@@ -21,4 +21,8 @@ REACT_APP_SHOW_DOWNLOAD=0
REACT_APP_DNS1='dns1.mermsemr.net'
REACT_APP_DNS2='dns1.mermsemr.net'
REACT_APP_DNS_LINK='https://www.mermsemr.com/info/dns'
REACT_APP_DNS_LINK='https://www.mermsemr.com/info/dns'
#CLOUDFLARE
REACT_APP_TURNSTILE_SITE_KEY=0x4AAAAAADQV82wuocFR-u5O
+5 -1
View File
@@ -18,4 +18,8 @@ REACT_APP_TIMEOUT=600000
REACT_APP_DNS1='dns1.mermsemr.net'
REACT_APP_DNS2='dns1.mermsemr.net'
REACT_APP_DNS_LINK='https://qa-www.mermsemr.com/info/dns'
REACT_APP_DNS_LINK='https://qa-www.mermsemr.com/info/dns'
#CLOUDFLARE
REACT_APP_TURNSTILE_SITE_KEY=0x4AAAAAADQV82wuocFR-u5O
+1 -1
View File
@@ -1,4 +1,4 @@
version: '3'
# version: '3'
services:
merms-panel:
# image: registry.chiefsoft.net/merms-panel-reactjs:latest
+11888 -5899
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -8,6 +8,7 @@
"@fullcalendar/interaction": "^6.1.15",
"@fullcalendar/react": "^6.1.15",
"@fullcalendar/timegrid": "^6.1.15",
"@marsidev/react-turnstile": "^1.5.2",
"@popperjs/core": "^2.11.8",
"@reduxjs/toolkit": "^2.4.0",
"@stripe/react-stripe-js": "^3.9.1",
+1 -1
View File
@@ -56,7 +56,7 @@ export default function CSignup() {
},
onSuccess: (res) => {
if(res?.data?.resultCode != '0'){
throw({message: res?.data?.resultDescription})
throw({message: res?.data?.error_message})
}
const {token, room, uid} = res?.data
if(!token || !room){
+17 -5
View File
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from 'react'
import { Form, Formik } from "formik";
import { Turnstile } from '@marsidev/react-turnstile'
import * as Yup from "yup";
// import LoginImg from '../../assets/bg/login.svg'
@@ -17,13 +18,14 @@ const validationSchema = Yup.object().shape({
// /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
// "Invalid email format"
// )
.min(3, "Minimum 3 characters")
.max(25, "Maximum 25 characters")
.required("Email is required"),
.min(3, "Username must be at least 3 characters")
.max(25, "Entered Username is too long")
.required("Enter a valid username to continue"),
})
const initialValues = {
username: ''
username: '',
turnstileToken: ''
};
export default function Forgetpwd2() {
@@ -77,8 +79,18 @@ export default function Forgetpwd2() {
</div>
</>
}
<div className="text-center col-12 mt-3">
<Turnstile
siteKey={process.env.REACT_APP_TURNSTILE_SITE_KEY}
onSuccess={(token) => props.setFieldValue('turnstileToken', token)}
onExpire={() => props.setFieldValue('turnstileToken', null)}
onError={() => props.setFieldValue('turnstileToken', null)}
/>
</div>
<div className="col-12 mt-3 text-end">
<button type='submit' className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Send'}</button>
<button type='submit' disabled={!props.values.turnstileToken || mutation.isPending} className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Send'}</button>
</div>
</>
:
+17 -6
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react'
import { useMutation } from '@tanstack/react-query'
import { useDispatch, useSelector } from 'react-redux'
import { Turnstile } from '@marsidev/react-turnstile'
// import LoginImg from '../../assets/bg/login.svg'
@@ -26,6 +27,8 @@ export default function Login() {
remember: false
})
const [turnstileToken, setTurnstileToken] = useState(null)
const handleChange = ({target:{name, value}}) => {
if(name == 'remember'){
return setFields(prev => ({...prev, remember:!prev.remember}))
@@ -34,13 +37,13 @@ export default function Login() {
}
const login = useMutation({
mutationFn: (fields) => {
mutationFn: ({ turnstileToken, ...fields }) => {
if(!fields.username || !fields.password){
throw new Error('Please provide all fields marked *')
}
rememberMe(fields.remember) // FUNCTION TO SAVE USERNAME OF THE USER TO LOCAL STORAGE
delete fields.remember // REMOVING REMEMBER FROM THE PAYLOAD
return loginUser(fields)
rememberMe(fields.remember)
delete fields.remember
return loginUser({ ...fields, turnstileToken })
},
onError: (error) => {
console.log(error)
@@ -69,7 +72,7 @@ export default function Login() {
}
}
useEffect(()=>{ // NAVIGATES USER TO HOME PAGE IF USER IS ACTIVE
useEffect(()=>{ // NAVIGATES USER TO HOME PAGE IF USER IS CURRENTLY ACTIVE
if(loggedIn){
navigate(siteLinks.dash)
}
@@ -101,6 +104,14 @@ export default function Login() {
<input maxLength={25} name='password' value={fields.password} onChange={handleChange} type="password" className="form-control" placeholder="Password" />
</div>
</div>
<div className="text-center col-12 mt-3">
<Turnstile
siteKey={process.env.REACT_APP_TURNSTILE_SITE_KEY}
onSuccess={setTurnstileToken}
onExpire={() => setTurnstileToken(null)}
onError={() => setTurnstileToken(null)}
/>
</div>
<div className="col-12">
<div className="d-block d-sm-flex align-items-center">
<div className="form-check">
@@ -120,7 +131,7 @@ export default function Login() {
</>
}
<div className="col-12 mt-3 text-end">
<button type='button' onClick={()=>{login.mutate(fields)}} className="btn btn-primary text-uppercase">{login.isPending ? 'loading...' : 'Sign In'}</button>
<button type='button' onClick={()=>{login.mutate({...fields, turnstileToken})}} disabled={!turnstileToken || login.isPending} className="btn btn-primary text-uppercase">{login.isPending ? 'loading...' : 'Sign In'}</button>
</div>
<div className="col-12 mt-3">
<p> <Link to={siteLinks.signup}>
+11 -1
View File
@@ -1,5 +1,6 @@
import React, {useState} from 'react'
import {Form, Formik} from "formik";
import { Turnstile } from '@marsidev/react-turnstile'
import * as Yup from "yup";
// import LoginImg from '../../assets/bg/login.svg'
@@ -33,6 +34,7 @@ const initialValues = {
firstname: '',
lastname: '',
isChecked: false,
turnstileToken: '',
// username: '',
// password: ''
};
@@ -157,9 +159,17 @@ export default function Signup2() {
</div>
</>
}
<div className="text-center col-12 mt-3">
<Turnstile
siteKey={process.env.REACT_APP_TURNSTILE_SITE_KEY}
onSuccess={(token) => props.setFieldValue('turnstileToken', token)}
onExpire={() => props.setFieldValue('turnstileToken', null)}
onError={() => props.setFieldValue('turnstileToken', null)}
/>
</div>
<div className="col-12 mt-3 text-end">
<button type='submit'
disabled={!props.values.turnstileToken || mutation.isPending}
className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Sign up'}</button>
</div>
</>
+26 -10
View File
@@ -42,18 +42,34 @@ export default function SocketIOContextProvider({children}) {
// setSocketMsgReceived(data.message);
// dispatch(tableReload({type:'CHATMESSAGELIST'})) // dispatches to update chat message sending from owner to worker and vice versa
console.log('SOCKET RECEIVED DATA *** ', data)
queryClient.refetchQueries({
queryKey: [...queryKeys.recentAction],
// type: 'active',
// exact: true,
})
if(data?.message_action === socketOnEvents.refresh_all_actions){
queryClient.refetchQueries({
queryKey: [...queryKeys.recentAction],
// type: 'active',
// exact: true,
})
}
if(data?.message_action === socketOnEvents.refresh_provision){
queryClient.refetchQueries({ // refetches product Page API call
queryKey: [...queryKeys.product_page],
})
queryClient.refetchQueries({ // refetches productProvision API call
queryKey: [...queryKeys.myproduct_provision],
})
}
});
socket.on(socketOnEvents.refresh_provision, (data) => {
queryClient.refetchQueries({ // refetches productProvision API call
queryKey: [...queryKeys.myproduct_provision],
})
});
// socket.on(socketOnEvents.refresh_provision, (data) => {
// queryClient.refetchQueries({ // refetches productProvision API call
// queryKey: [...queryKeys.myproduct_provision],
// })
// // queryClient.invalidateQueries({ queryKey: [...queryKeys.product_page] })
// queryClient.refetchQueries({ // refetches product Page API call
// queryKey: [...queryKeys.product_page],
// })
// console.log('SOCKET RECEIVED DATA *** 111 ', data)
// });
// client-side
socket.on("connect", () => {
+1
View File
@@ -6,5 +6,6 @@ export const socketEmitEvents = {
export const socketOnEvents = {
receive_message: 'receive_message',
refresh_all_actions: 'refresh_all_actions',
refresh_provision: 'refresh_provision_actions'
}
+1 -1
View File
@@ -47,7 +47,7 @@ export default function Products() {
return (
<div key={product.uid+index} className={`col-12 col-lg-6 mb-2 mb-xxl-0`}>
<Link to={productPath(product?.product_id)} >
<div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px'}} >
<div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px', paddingLeft:"1px"}} >
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
<i className={`fa ${product?.product_icon} text-primary`}></i>
</div>
@@ -11,7 +11,7 @@ export default function UserFooter(){
<p>&copy; Copyright {year}. All rights reserved.</p>
</div>
<div className="col col-sm-6 ml-sm-auto text-center text-sm-right">
<p>A division of autoMedSys A.I.</p>
<p>A division of MERMS(AI)</p>
</div>
</div>
</footer>
@@ -84,6 +84,7 @@ const TemplateConfigure = ({ productData }) => {
backgroundColor: "aliceblue",
margin: "2px",
maxHeight: "150px",
width: "100%",
}}
>
<div
+1
View File
@@ -72,6 +72,7 @@ export default function ProfileForm({data}) {
const handleSetInfoToUpdate = (values, helpers) => {
delete values.email
delete values.country
delete values?.picture
setInfoToUpdate(values)
var modal = new Modal(document.getElementById('modal'));
modal.show();
@@ -1,57 +1,85 @@
import React from 'react';
import { loadStripe } from '@stripe/stripe-js';
import { Elements, useStripe, useElements, CardElement } from '@stripe/react-stripe-js';
import {MyProductData, StripeSubscriptionCreate} from '../../services/services';
import {useQuery} from "@tanstack/react-query";
import React from "react";
import { loadStripe } from "@stripe/stripe-js";
import {
Elements,
useStripe,
useElements,
CardElement,
} from "@stripe/react-stripe-js";
import {
MyProductData,
StripeSubscriptionCreate,
} from "../../services/services";
import { useQuery } from "@tanstack/react-query";
import queryKeys from "../../services/queryKeys";
import { useNavigate } from 'react-router-dom';
import { useNavigate } from "react-router-dom";
//const stripePromise = loadStripe('your_stripe_publishable_key');
const stripePromise = loadStripe('pk_test_51RqL5WLjZLojw6IZmEpwFidNZSl9lLlVUHNvuFZNEz1eTR9XXepnyyVhfvXe9cp4eMnqkDPpoe9wxLLRSV0dxRee00UfhayUOT');
const stripePromise = loadStripe(
"pk_test_51RqL5WLjZLojw6IZmEpwFidNZSl9lLlVUHNvuFZNEz1eTR9XXepnyyVhfvXe9cp4eMnqkDPpoe9wxLLRSV0dxRee00UfhayUOT",
);
const CheckoutForm = ({ priceId, customerId ,option_name }) => {
const stripe = useStripe();
const elements = useElements();
const navigate = useNavigate();
const handleSubmit = async (event) => {
event.preventDefault();
const CheckoutForm = ({
priceId,
customerId,
option_name,
selected_display_name,
}) => {
const stripe = useStripe();
const elements = useElements();
const navigate = useNavigate();
const handleSubmit = async (event) => {
event.preventDefault();
if (!stripe || !elements) {
return;
}
let reqData = {
priceId : priceId,
customerId: customerId,
option_name: option_name,
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
StripeSubscriptionCreate(reqData).then( (res)=>{
console.log(res);
console.log(res.data.stripe_session);
//navigate(res.data.stripe_session)
window.location.replace(res.data.stripe_session);
});
if (!stripe || !elements) {
return;
}
let reqData = {
priceId: priceId,
customerId: customerId,
option_name: option_name,
token: localStorage.getItem("token"), // USER TOKEN
uid: localStorage.getItem("uid"), // USER UID
};
return (
<form onSubmit={handleSubmit}>
<CardElement />
<button type="submit" disabled={!stripe}>
Subscribe
</button>
</form>
);
StripeSubscriptionCreate(reqData).then((res) => {
console.log(res);
console.log(res.data.stripe_session);
//navigate(res.data.stripe_session)
window.location.replace(res.data.stripe_session);
});
};
return (
<form onSubmit={handleSubmit}>
{/*<CardElement />*/}
<button
type="submit"
disabled={!stripe}
className="btn btn-primary text-uppercase"
>
Start {selected_display_name} Subscription
</button>
</form>
);
};
const StripeSubscriptionButton = ({ priceId, customerId ,option_name}) => {
return (
<Elements stripe={stripePromise}>
<CheckoutForm priceId={priceId} customerId={customerId} option_name={option_name} />
</Elements>
);
const StripeSubscriptionButton = ({
priceId,
customerId,
option_name,
selected_display_name,
}) => {
return (
<Elements stripe={stripePromise}>
<CheckoutForm
priceId={priceId}
customerId={customerId}
option_name={option_name}
selected_display_name={selected_display_name}
/>
</Elements>
);
};
export default StripeSubscriptionButton;
export default StripeSubscriptionButton;
+19 -15
View File
@@ -5,15 +5,14 @@ import SubscribeNewCard from "./SubscribeNewCard";
import SubscribePreviousCard from "./SubscribePreviousCard";
import SubcribePaymentOptions from "./SubcribePaymentOptions";
import StripeSubscriptionButton from "./StripeSubscriptionButton";
import SubscribeInfo from "./SubscribeInfo";
export default function Subscribe() {
const {state: {selectedSubscription,customerId}} = useLocation()
const {state: {selectedSubscription, customerId, currentSubscription}} = useLocation()
console.log('selectedSubscription', selectedSubscription)
console.log('selectedSubscription.option_name',selectedSubscription.option_name)
console.log('currentSubscription', currentSubscription)
console.log('selectedSubscription.option_name', selectedSubscription.option_name)
console.log('customerId', customerId)
let [activePaymentType, setActivePaymentType] = useState('previous')
@@ -27,17 +26,22 @@ export default function Subscribe() {
<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">{currentSubscription?.display_name}</h2>*/}
<SubcribePaymentOptions activePaymentType={activePaymentType}
setActivePaymentType={setActivePaymentType}/>
{activePaymentType == 'new' ?
<SubscribeNewCard/>
:
<SubscribePreviousCard/>
}
<h3>Your Current Subscription</h3>
<h2 className="text-primary pt-3">{currentSubscription?.display_name}</h2>
{/*<SubcribePaymentOptions activePaymentType={activePaymentType}*/}
{/* setActivePaymentType={setActivePaymentType}/>*/}
{/*{activePaymentType == 'new' ?*/}
{/* <SubscribeNewCard/>*/}
{/* :*/}
{/* <SubscribePreviousCard/>*/}
{/*}*/}
<>
<StripeSubscriptionButton priceId={selectedSubscription.stripe_price_id} customerId={customerId} option_name={selectedSubscription.option_name} />
<SubscribeInfo />
<StripeSubscriptionButton priceId={selectedSubscription.stripe_price_id}
customerId={customerId}
option_name={selectedSubscription.option_name}
selected_display_name={selectedSubscription.display_name}
/>
</>
</div>
</div>
+25
View File
@@ -0,0 +1,25 @@
import React from 'react'
export default function SubscribeInfo() {
return <>
<div className="row">
<div className="col-md-12 col-12 selects-contant">
<div className="card card-statistics">
<div className="card-body">
<div className="form-group mb-0">
Your subscription terms outline the details of your plan, including billing frequency,
renewal dates, payment methods, and cancellation policies. Please review your subscription
agreement for information on your current plan, how to manage or update your subscription,
and any applicable fees or renewal conditions. Contact support if you have questions about
your subscription.
</div>
</div>
</div>
</div>
</div>
</>
}
+2 -1
View File
@@ -91,7 +91,8 @@ export default function Subscription() {
navigate(siteLinks.subscribe, {
state: {
selectedSubscription: value,
customerId: stripe_customer_id
customerId: stripe_customer_id,
currentSubscription: currentSubscription
}
})
}}
+1 -1
View File
@@ -2072,7 +2072,7 @@ ul.activity {
}
.img-icon i{
font-size:20px;
font-size:35px;
}
@media (max-width: 1440px) and (min-width:1200px){
.border-xxl-t{